diff --git a/Android.mk b/Android.mk index 1246c73cf16f6193035d6cfe7b08b93906b027db..ca76fb4b74de60c2c2c79795acc2b6ddc10e064f 100644 --- a/Android.mk +++ b/Android.mk @@ -41,9 +41,21 @@ LOCAL_SRC_FILES := $(filter-out \ org/mobilecontrol/% \ ,$(LOCAL_SRC_FILES)) +# Include a different set of source files when building a debug build. +# TODO: Maybe build these into a separate .jar and put it on the classpath +# in front of framework.jar. +# NOTE: Do not use this as an example; this is a very special situation. +# Do not modify LOCAL_SRC_FILES based on any variable other +# than TARGET_BUILD_TYPE, otherwise builds can become inconsistent. +ifeq ($(TARGET_BUILD_TYPE),debug) + LOCAL_SRC_FILES += $(call find-other-java-files,core/config/debug) +else + LOCAL_SRC_FILES += $(call find-other-java-files,core/config/ndebug) +endif + ## READ ME: ######################################################## ## -## When updading this list of aidl files, consider if that aidl is +## When updating this list of aidl files, consider if that aidl is ## part of the SDK API. If it is, also add it to the list below that ## is preprocessed and distributed with the SDK. This list should ## not contain any aidl files for parcelables, but the one below should @@ -67,12 +79,16 @@ LOCAL_SRC_FILES += \ core/java/android/app/ITransientNotification.aidl \ core/java/android/app/IWallpaperService.aidl \ core/java/android/app/IWallpaperServiceCallback.aidl \ + core/java/android/backup/IBackupManager.aidl \ + core/java/android/backup/IBackupService.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 \ + core/java/android/content/IContentService.aidl \ core/java/android/content/ISyncAdapter.aidl \ core/java/android/content/ISyncContext.aidl \ + core/java/android/content/ISyncStatusObserver.aidl \ core/java/android/content/pm/IPackageDataObserver.aidl \ core/java/android/content/pm/IPackageDeleteObserver.aidl \ core/java/android/content/pm/IPackageInstallObserver.aidl \ @@ -96,10 +112,13 @@ LOCAL_SRC_FILES += \ core/java/android/view/IWindow.aidl \ core/java/android/view/IWindowManager.aidl \ core/java/android/view/IWindowSession.aidl \ + core/java/android/speech/IRecognitionListener.aidl \ + core/java/android/speech/IRecognitionService.aidl \ core/java/com/android/internal/app/IBatteryStats.aidl \ core/java/com/android/internal/app/IUsageStats.aidl \ core/java/com/android/internal/appwidget/IAppWidgetService.aidl \ core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \ + core/java/com/android/internal/backup/IBackupTransport.aidl \ core/java/com/android/internal/os/IResultReceiver.aidl \ core/java/com/android/internal/view/IInputContext.aidl \ core/java/com/android/internal/view/IInputContextCallback.aidl \ @@ -109,9 +128,13 @@ LOCAL_SRC_FILES += \ 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/IGeocodeProvider.aidl \ location/java/android/location/IGpsStatusListener.aidl \ + location/java/android/location/IGpsStatusProvider.aidl \ + location/java/android/location/ILocationCollector.aidl \ location/java/android/location/ILocationListener.aidl \ location/java/android/location/ILocationManager.aidl \ + location/java/android/location/ILocationProvider.aidl \ media/java/android/media/IAudioService.aidl \ media/java/android/media/IMediaScannerListener.aidl \ media/java/android/media/IMediaScannerService.aidl \ @@ -119,8 +142,8 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \ telephony/java/com/android/internal/telephony/ITelephony.aidl \ telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \ - telephony/java/com/android/internal/telephony/gsm/ISimPhoneBook.aidl \ - telephony/java/com/android/internal/telephony/gsm/ISms.aidl \ + telephony/java/com/android/internal/telephony/IIccPhoneBook.aidl \ + telephony/java/com/android/internal/telephony/ISms.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl \ telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl @@ -221,6 +244,11 @@ fwbase_dirs_to_document := \ ) \ ) +# Pass a special "fake-out" version of some classes to the doc/API tools. +# ConfigBuildFlags uses this trick to prevent certain fields from appearing +# as "final" in the official SDK APIs. +fwbase_dirs_to_document += core/config/sdk + # These are relative to dalvik/libcore # Intentionally not included from libcore: # icu openssl suncompat support @@ -292,12 +320,6 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \ 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 web_docs_sample_code_flags := \ @@ -309,6 +331,19 @@ web_docs_sample_code_flags := \ -samplecode $(sample_dir)/NotePad \ guide/samples/NotePad "Note Pad" +# SDK version identifiers used in the published docs. + +# major[.minor] version for SDK. Typically identical to the +# most current Android platform version included in the SDK package. +framework_docs_SDK_VERSION := 1.5 +# release version for SDK (ie "Release x") +framework_docs_SDK_REL_ID := 1 +framework_docs_SDK_CURRENT_DIR := $(framework_docs_SDK_VERSION)_r$(framework_docs_SDK_REL_ID) + +framework_docs_LOCAL_DROIDDOC_OPTIONS += \ + -hdf sdk.version $(framework_docs_SDK_VERSION) \ + -hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \ + -hdf sdk.current $(framework_docs_SDK_CURRENT_DIR) # ==== static html in the sdk ================================== include $(CLEAR_VARS) @@ -341,7 +376,7 @@ include $(BUILD_DROIDDOC) static_doc_index_redirect := $(out_dir)/index.html $(static_doc_index_redirect): \ - $(LOCAL_PATH)/docs/docs-documentation-redirect.html | $(ACP) + $(LOCAL_PATH)/docs/docs-documentation-redirect.html | $(ACP) $(hide) mkdir -p $(dir $@) $(hide) $(ACP) $< $@ @@ -366,10 +401,10 @@ LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR) LOCAL_MODULE := online-sdk LOCAL_DROIDDOC_OPTIONS:= \ - $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ - $(web_docs_sample_code_flags) \ - -toroot / \ - -hdf android.whichdoc online + $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ + $(web_docs_sample_code_flags) \ + -toroot / \ + -hdf android.whichdoc online LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk @@ -432,3 +467,5 @@ include $(BUILD_JAVA_LIBRARY) ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif + + diff --git a/api/1.xml b/api/1.xml index b196ac776ed9932ba7a4b3d3a57e30d688b201c9..02e8eace5614f46a2c434817d6993f300978d79a 100644 --- a/api/1.xml +++ b/api/1.xml @@ -88531,7 +88531,7 @@ deprecated="not deprecated" visibility="public" > - + - + diff --git a/api/2.xml b/api/2.xml index b9736fe735974f778e74bfb6cf6a1facf7603e31..65e7cec1be363beb595444de097c8c482eef8c17 100644 --- a/api/2.xml +++ b/api/2.xml @@ -88575,7 +88575,7 @@ deprecated="not deprecated" visibility="public" > - + - + diff --git a/api/4.xml b/api/4.xml new file mode 100644 index 0000000000000000000000000000000000000000..893301e10009968e8f8c55a7be3405869ffbc5df --- /dev/null +++ b/api/4.xml @@ -0,0 +1,334770 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/api/current.xml b/api/current.xml index d646f4f5feb1a7d40dcf2488c26d50081355a59e..eaf15122da2bdadb2aba27a0b094fdf75038c6a2 100644 --- a/api/current.xml +++ b/api/current.xml @@ -529,6 +529,28 @@ visibility="public" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -63648,7 +63625,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -68364,6 +68341,17 @@ visibility="public" > + + + + + + + + + + - - - - - - - - + - - - + - - - + + + + + - + - - + + + - + - + - - + + + + + - + + - + + + + + + + + - + + + + + + + + - - + - + + - - + - - + - - + + + + + + + - - - - - - + - + - + - + - - + + + + + + + - - + + + + + + + - - + + + + + + + + + + + + + + + - - + + + + + + + + + + + - + - + - - + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + - - - - - - - - - - - + + + - + - + + + - - - - + + + - - - + + + - + - - - - + - + - - + - + - - - - - - + - - - - - - - - - - - - - - - - - - - - + - - - - - - + - + - + - - - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - + - - - + - - - - + + + - - - - - - + - + - + - - - - - - - - - - + - + - - - - - - + - + - - - - - - + - + - + - - - - - - - - - - - - + - + - - - - - + + + - - - - @@ -73897,48 +73873,52 @@ - + - + - - + - + - + - + + + + + - - + - + - + - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - - + - + - + + + - - - - - - - - - - + - + - - - - - - - - - - - - + - + - - - - - - + - + - + - - + - + - - - - - - - - + - + - - - - - - - - + - + - + - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -75137,6 +85575,16 @@ visibility="public" > + + + + + + + + + + + + + + @@ -81631,6 +92139,19 @@ visibility="public" > + + + + + + + + + + + + + + + + @@ -95723,8 +106274,8 @@ native="false" synchronized="false" static="true" - final="false" - deprecated="not deprecated" + final="true" + deprecated="deprecated" visibility="public" > @@ -95734,8 +106285,8 @@ native="false" synchronized="false" static="false" - final="false" - deprecated="not deprecated" + final="true" + deprecated="deprecated" visibility="public" > @@ -95757,8 +106308,8 @@ native="false" synchronized="false" static="false" - final="false" - deprecated="not deprecated" + final="true" + deprecated="deprecated" visibility="public" > @@ -95778,8 +106329,8 @@ native="false" synchronized="false" static="false" - final="false" - deprecated="not deprecated" + final="true" + deprecated="deprecated" visibility="public" > @@ -95800,7 +106351,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95811,7 +106362,7 @@ value="4" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95822,7 +106373,7 @@ value="3" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95833,7 +106384,7 @@ value="2" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95844,7 +106395,7 @@ value="0" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95855,7 +106406,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95866,7 +106417,7 @@ value="5" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95877,7 +106428,7 @@ value="3" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95888,7 +106439,7 @@ value="7" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95898,14 +106449,14 @@ abstract="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95916,7 +106467,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95931,7 +106482,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95946,7 +106497,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95959,7 +106510,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95970,7 +106521,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95981,7 +106532,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -95992,7 +106543,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96003,7 +106554,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96014,7 +106565,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96025,7 +106576,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96036,7 +106587,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96047,7 +106598,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96058,7 +106609,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96069,7 +106620,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96080,7 +106631,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96091,7 +106642,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96102,7 +106653,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96113,7 +106664,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96132,7 +106683,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96153,7 +106704,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96166,7 +106717,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96177,7 +106728,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96188,7 +106739,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96199,7 +106750,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96210,7 +106761,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96221,7 +106772,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96232,7 +106783,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96243,7 +106794,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96254,7 +106805,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96265,7 +106816,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96276,7 +106827,7 @@ value="3" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96287,7 +106838,7 @@ value="1" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96298,7 +106849,7 @@ value="2" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96309,7 +106860,7 @@ value="0" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96320,7 +106871,7 @@ value="140" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96331,7 +106882,7 @@ value="160" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96342,7 +106893,7 @@ value="153" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96352,7 +106903,7 @@ abstract="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96403,7 +106954,7 @@ value="null" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -96414,7 +106965,7 @@ value="null" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -101178,23 +111729,6 @@ - - - - - - - - @@ -114962,7 +125495,7 @@ value="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -114973,7 +125506,7 @@ value="false" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -114981,10 +125514,9 @@ type="boolean" transient="false" volatile="false" - value="true" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > @@ -125211,6 +135743,19 @@ visibility="public" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + & args) const String8 result; AutoMutex lock(&mLock); if (mFakeCamera != 0) { - mFakeCamera->dump(fd, args); + mFakeCamera->dump(fd); mParameters.dump(fd, args); snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false"); result.append(buffer); diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index cb8ab58827c094dd491a3970dc325426c46768b3..f85ea9f85054c4a43c8bbfe471dff35771a78426 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -217,7 +217,13 @@ status_t CameraService::Client::unlock() // allow anyone to use camera LOGV("unlock (%p)", getCameraClient()->asBinder().get()); status_t result = checkPid(); - if (result == NO_ERROR) mClientPid = 0; + if (result == NO_ERROR) { + mClientPid = 0; + + // we need to remove the reference so that when app goes + // away, the reference count goes to 0. + mCameraClient.clear(); + } return result; } @@ -894,8 +900,6 @@ status_t CameraService::Client::setParameters(const String8& params) // get preview/capture parameters - key/value pairs String8 CameraService::Client::getParameters() const { - LOGD("getParameters"); - Mutex::Autolock lock(mLock); if (mHardware == 0) { @@ -903,30 +907,32 @@ String8 CameraService::Client::getParameters() const return String8(); } - return mHardware->getParameters().flatten(); + String8 params(mHardware->getParameters().flatten()); + LOGD("getParameters(%s)", params.string()); + return params; } void CameraService::Client::postAutoFocus(bool focused) { LOGV("postAutoFocus"); - mCameraClient->autoFocusCallback(focused); + mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, (int32_t)focused, 0); } void CameraService::Client::postShutter() { - mCameraClient->shutterCallback(); + mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0); } void CameraService::Client::postRaw(const sp& mem) { LOGD("postRaw"); - mCameraClient->rawCallback(mem); + mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem); } void CameraService::Client::postJpeg(const sp& mem) { LOGD("postJpeg"); - mCameraClient->jpegCallback(mem); + mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem); } void CameraService::Client::copyFrameAndPostCopiedFrame(sp heap, size_t offset, size_t size) @@ -954,7 +960,7 @@ void CameraService::Client::copyFrameAndPostCopiedFrame(sp heap, si LOGE("failed to allocate space for frame callback"); return; } - mCameraClient->previewCallback(frame); + mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame); } void CameraService::Client::postRecordingFrame(const sp& frame) @@ -964,7 +970,7 @@ void CameraService::Client::postRecordingFrame(const sp& frame) LOGW("frame is a null pointer"); return; } - mCameraClient->recordingCallback(frame); + mCameraClient->dataCallback(CAMERA_MSG_VIDEO_FRAME, frame); } void CameraService::Client::postPreviewFrame(const sp& mem) @@ -998,7 +1004,7 @@ void CameraService::Client::postPreviewFrame(const sp& mem) copyFrameAndPostCopiedFrame(heap, offset, size); } else { LOGV("frame is directly sent out without copying"); - mCameraClient->previewCallback(mem); + mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem); } // Is this is one-shot only? @@ -1012,7 +1018,7 @@ void CameraService::Client::postPreviewFrame(const sp& mem) void CameraService::Client::postError(status_t error) { - mCameraClient->errorCallback(error); + mCameraClient->notifyCallback(CAMERA_MSG_ERROR, error, 0); } status_t CameraService::dump(int fd, const Vector& args) diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp index 3592eabcb92d41fd7ceb33625b007af2f464df7e..3daf47dbadeb9241e8cf599f03ca40d590227b1a 100644 --- a/camera/libcameraservice/FakeCamera.cpp +++ b/camera/libcameraservice/FakeCamera.cpp @@ -1,12 +1,39 @@ +/* +** +** 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 "FakeCamera" #include #include #include +#include + #include "FakeCamera.h" + namespace android { +// TODO: All this rgb to yuv should probably be in a util class. + +// TODO: I think something is wrong in this class because the shadow is kBlue +// and the square color should alternate between kRed and kGreen. However on the +// emulator screen these are all shades of gray. Y seems ok but the U and V are +// probably not. + static int tables_initialized = 0; uint8_t *gYTable, *gCbTable, *gCrTable; @@ -389,7 +416,7 @@ void FakeCamera::drawCheckerboard(uint16_t *dst, int size) } -status_t FakeCamera::dump(int fd, const Vector& args) +void FakeCamera::dump(int fd) const { const size_t SIZE = 256; char buffer[SIZE]; @@ -397,7 +424,6 @@ status_t FakeCamera::dump(int fd, const Vector& args) snprintf(buffer, 255, " width x height (%d x %d), counter (%d), check x-y coordinate(%d, %d)\n", mWidth, mHeight, mCounter, mCheckX, mCheckY); result.append(buffer); ::write(fd, result.string(), result.size()); - return NO_ERROR; } diff --git a/camera/libcameraservice/FakeCamera.h b/camera/libcameraservice/FakeCamera.h index 77c994c1afb1ad8ed6703797e0f3bf67f6a60e86..f7f880328a4c416a2b52ff86e1098c6fe4e9a53d 100644 --- a/camera/libcameraservice/FakeCamera.h +++ b/camera/libcameraservice/FakeCamera.h @@ -18,21 +18,37 @@ #ifndef ANDROID_HARDWARE_FAKECAMERA_H #define ANDROID_HARDWARE_FAKECAMERA_H -#include +#include +#include namespace android { +/* + * FakeCamera is used in the CameraHardwareStub to provide a fake video feed + * when the system does not have a camera in hardware. + * The fake video is a moving black and white checkerboard background with a + * bouncing gray square in the foreground. + * This class is not thread-safe. + * + * TODO: Since the major methods provides a raw/uncompressed video feed, rename + * this class to RawVideoSource. + */ + class FakeCamera { public: FakeCamera(int width, int height); ~FakeCamera(); void setSize(int width, int height); - void getNextFrameAsRgb565(uint16_t *buffer); void getNextFrameAsYuv422(uint8_t *buffer); - status_t dump(int fd, const Vector& args); + // Write to the fd a string representing the current state. + void dump(int fd) const; private: + // TODO: remove the uint16_t buffer param everywhere since it is a field of + // this class. + void getNextFrameAsRgb565(uint16_t *buffer); + void drawSquare(uint16_t *buffer, int x, int y, int size, int color, int shadow); void drawCheckerboard(uint16_t *buffer, int size); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 161bb462ddf83d17c503447df6381c80c886fcc9..8212b9212af8d8ad5dc8600a0225acafa341f059 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -537,6 +537,12 @@ public final class Pm { case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER: s = "INSTALL_FAILED_CONFLICTING_PROVIDER"; break; + case PackageManager.INSTALL_FAILED_NEWER_SDK: + s = "INSTALL_FAILED_NEWER_SDK"; + break; + case PackageManager.INSTALL_FAILED_TEST_ONLY: + s = "INSTALL_FAILED_TEST_ONLY"; + break; case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: s = "INSTALL_PARSE_FAILED_NOT_APK"; break; @@ -576,13 +582,23 @@ public final class Pm { private void runInstall() { int installFlags = 0; + String installerPackageName = null; String opt; while ((opt=nextOption()) != null) { if (opt.equals("-l")) { - installFlags |= PackageManager.FORWARD_LOCK_PACKAGE; + installFlags |= PackageManager.INSTALL_FORWARD_LOCK; } else if (opt.equals("-r")) { - installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE; + installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; + } else if (opt.equals("-i")) { + installerPackageName = nextOptionData(); + if (installerPackageName == null) { + System.err.println("Error: no value specified for -i"); + showUsage(); + return; + } + } else if (opt.equals("-t")) { + installFlags |= PackageManager.INSTALL_ALLOW_TEST; } else { System.err.println("Error: Unknown option: " + opt); showUsage(); @@ -600,7 +616,8 @@ public final class Pm { PackageInstallObserver obs = new PackageInstallObserver(); try { - mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags); + mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, + installerPackageName); synchronized (obs) { while (!obs.finished) { @@ -809,37 +826,39 @@ public final class Pm { 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 install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); System.err.println(" pm enable PACKAGE_OR_COMPONENT"); System.err.println(" pm disable PACKAGE_OR_COMPONENT"); System.err.println(""); - System.err.println("The list packages command prints all packages. Use"); - System.err.println("the -f option to see their associated file."); + System.err.println("The list packages command prints all packages. Options:"); + System.err.println(" -f: see their associated file."); System.err.println(""); System.err.println("The list permission-groups command prints all known"); System.err.println("permission groups."); System.err.println(""); System.err.println("The list permissions command prints all known"); - System.err.println("permissions, optionally only those in GROUP. Use"); - System.err.println("the -g option to organize by group. Use"); - System.err.println("the -f option to print all information. Use"); - System.err.println("the -s option for a short summary. Use"); - 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("permissions, optionally only those in GROUP. Options:"); + System.err.println(" -g: organize by group."); + System.err.println(" -f: print all information."); + System.err.println(" -s: short summary."); + System.err.println(" -d: only list dangerous permissions."); + System.err.println(" -u: 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("or only those that target a specified package. Options:"); + System.err.println(" -f: 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"); - System.err.println("the -l option to install the package with FORWARD_LOCK. Use"); - System.err.println("the -r option to reinstall an exisiting app, keeping its data."); + System.err.println("The install command installs a package to the system. Options:"); + System.err.println(" -l: install the package with FORWARD_LOCK."); + System.err.println(" -r: reinstall an exisiting app, keeping its data."); + System.err.println(" -t: allow test .apks to be installed."); + System.err.println(" -i: specify the installer package name."); System.err.println(""); - System.err.println("The uninstall command removes a package from the system. Use"); - System.err.println("the -k option to keep the data and cache directories around"); + System.err.println("The uninstall command removes a package from the system. Options:"); + System.err.println(" -k: keep the data and cache directories around."); System.err.println("after the package removal."); System.err.println(""); System.err.println("The enable and disable commands change the enabled state of"); diff --git a/core/config/README.txt b/core/config/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f48fb309bd9b13f7e3889f238d0d1f09c3f7986 --- /dev/null +++ b/core/config/README.txt @@ -0,0 +1,5 @@ +One of the subdirectories {debug, ndebug} is included in framework.jar +by ../../Android.mk depending on the value of $(TARGET_BUILD_TYPE). + +The sdk/ directory contains the files that are passed to the doc/API +tools regardless of $(TARGET_BUILD_TYPE). diff --git a/core/config/debug/android/util/ConfigBuildFlags.java b/core/config/debug/android/util/ConfigBuildFlags.java new file mode 100644 index 0000000000000000000000000000000000000000..eb0016349f82c1ce9872c43e29814e501cf98227 --- /dev/null +++ b/core/config/debug/android/util/ConfigBuildFlags.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +/** + * Static flags set by the build process. + */ +/* package */ final class ConfigBuildFlags { + /* package */ static final boolean DEBUG = true; +} diff --git a/core/config/ndebug/android/util/ConfigBuildFlags.java b/core/config/ndebug/android/util/ConfigBuildFlags.java new file mode 100644 index 0000000000000000000000000000000000000000..2345a40c719c2fee3170525e77a6a9baebc9aec6 --- /dev/null +++ b/core/config/ndebug/android/util/ConfigBuildFlags.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +/** + * Static flags set by the build process. + */ +/* package */ final class ConfigBuildFlags { + /* package */ static final boolean DEBUG = false; +} diff --git a/core/config/sdk/android/util/ConfigBuildFlags.java b/core/config/sdk/android/util/ConfigBuildFlags.java new file mode 100644 index 0000000000000000000000000000000000000000..f903ee42d76d4b1dbc521e8e3bc386de79fb2ebc --- /dev/null +++ b/core/config/sdk/android/util/ConfigBuildFlags.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +/** + * Static flags set by the build process. + */ +/* package */ final class ConfigBuildFlags { + /* This field is intentionally declared as non-final. This file + * is passed to the SDK docs/API tools, and is used to force them + * to avoid treating DEBUG as a constant value. This is necessary + * to avoid breaking the API check when switching to and from + * a debug build. + */ + /* package */ static boolean DEBUG = false; +} diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 849a37dc95a964dfcac7637ea5dfc3135e84396b..9b1f0f97171f0ea29695cdca49ab8693b9b38a19 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -611,7 +611,7 @@ public class Activity extends ContextThemeWrapper private IBinder mToken; /*package*/ String mEmbeddedID; private Application mApplication; - private Intent mIntent; + /*package*/ Intent mIntent; private ComponentName mComponent; /*package*/ ActivityInfo mActivityInfo; /*package*/ ActivityThread mMainThread; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 53e6f34a691564b24565339eb7f813c68101550e..541f413676c8530215344b521f4cff90b0465f5f 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -990,6 +990,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case SHUTDOWN_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + boolean res = shutdown(data.readInt()); + reply.writeNoException(); + reply.writeInt(res ? 1 : 0); + return true; + } + case PEEK_SERVICE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); Intent service = Intent.CREATOR.createFromParcel(data); @@ -2160,5 +2168,19 @@ class ActivityManagerProxy implements IActivityManager return res; } + public boolean shutdown(int timeout) throws RemoteException + { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(timeout); + mRemote.transact(SHUTDOWN_TRANSACTION, data, reply, 0); + reply.readException(); + boolean res = reply.readInt() != 0; + reply.recycle(); + data.recycle(); + return res; + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d8161936a44d10ac1fac01fecb583c76190b1730..1e15d14271d3815816b92f1de0ce979a34bd64a4 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -161,7 +161,7 @@ public final class ActivityThread { return metrics; } - Resources getTopLevelResources(String appDir) { + Resources getTopLevelResources(String appDir, float applicationScale) { synchronized (mPackages) { //Log.w(TAG, "getTopLevelResources: " + appDir); WeakReference wr = mActiveResources.get(appDir); @@ -181,7 +181,22 @@ public final class ActivityThread { return null; } DisplayMetrics metrics = getDisplayMetricsLocked(false); - r = new Resources(assets, metrics, getConfiguration()); + // density used to load resources + // scaledDensity is calculated in Resources constructor + // + boolean usePreloaded = true; + + // TODO: use explicit flag to indicate the compatibility mode. + if (applicationScale != 1.0f) { + usePreloaded = false; + DisplayMetrics newMetrics = new DisplayMetrics(); + newMetrics.setTo(metrics); + float newDensity = metrics.density / applicationScale; + newMetrics.updateDensity(newDensity); + metrics = newMetrics; + } + //Log.i(TAG, "Resource:" + appDir + ", display metrics=" + metrics); + r = new Resources(assets, metrics, getConfiguration(), usePreloaded); //Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration()); // XXX need to remove entries when weak references go away mActiveResources.put(appDir, new WeakReference(r)); @@ -209,6 +224,8 @@ public final class ActivityThread { private Resources mResources; private ClassLoader mClassLoader; private Application mApplication; + private float mApplicationScale; + private final HashMap> mReceivers = new HashMap>(); private final HashMap> mUnregisteredReceivers @@ -241,8 +258,8 @@ public final class ActivityThread { mSystemContext = ApplicationContext.createSystemContext(mainThread); mSystemContext.getResources().updateConfiguration( - mainThread.getConfiguration(), - mainThread.getDisplayMetricsLocked(false)); + mainThread.getConfiguration(), + mainThread.getDisplayMetricsLocked(false)); //Log.i(TAG, "Created system resources " // + mSystemContext.getResources() + ": " // + mSystemContext.getResources().getConfiguration()); @@ -250,6 +267,8 @@ public final class ActivityThread { mClassLoader = mSystemContext.getClassLoader(); mResources = mSystemContext.getResources(); } + + mApplicationScale = -1.0f; } public PackageInfo(ActivityThread activityThread, String name, @@ -268,6 +287,7 @@ public final class ActivityThread { mIncludeCode = true; mClassLoader = systemContext.getClassLoader(); mResources = systemContext.getResources(); + mApplicationScale = systemContext.getApplicationScale(); } public String getPackageName() { @@ -278,6 +298,45 @@ public final class ActivityThread { return mSecurityViolation; } + public float getApplicationScale() { + if (mApplicationScale > 0.0f) { + return mApplicationScale; + } + DisplayMetrics metrics = mActivityThread.getDisplayMetricsLocked(false); + // Find out the density scale (relative to 160) of the supported density that + // is closest to the system's density. + try { + ApplicationInfo ai = getPackageManager().getApplicationInfo( + mPackageName, PackageManager.GET_SUPPORTS_DENSITIES); + + float appScale = -1.0f; + if (ai.supportsDensities != null) { + int minDiff = Integer.MAX_VALUE; + for (int density : ai.supportsDensities) { + int tmpDiff = (int) Math.abs(DisplayMetrics.DEVICE_DENSITY - density); + if (tmpDiff == 0) { + appScale = 1.0f; + break; + } + // prefer higher density (appScale>1.0), unless that's only option. + if (tmpDiff < minDiff && appScale < 1.0f) { + appScale = DisplayMetrics.DEVICE_DENSITY / density; + minDiff = tmpDiff; + } + } + } + if (appScale < 0.0f) { + mApplicationScale = metrics.density; + } else { + mApplicationScale = appScale; + } + } catch (RemoteException e) { + throw new AssertionError(e); + } + if (localLOGV) Log.v(TAG, "appScale=" + mApplicationScale + ", pkg=" + mPackageName); + return mApplicationScale; + } + /** * Gets the array of shared libraries that are listed as * used by the given package. @@ -435,7 +494,7 @@ public final class ActivityThread { public Resources getResources(ActivityThread mainThread) { if (mResources == null) { - mResources = mainThread.getTopLevelResources(mResDir); + mResources = mainThread.getTopLevelResources(mResDir, getApplicationScale()); } return mResources; } @@ -1689,7 +1748,7 @@ public final class ActivityThread { r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo); - handleLaunchActivity(r); + handleLaunchActivity(r, null); } break; case RELAUNCH_ACTIVITY: { ActivityRecord r = (ActivityRecord)msg.obj; @@ -2109,7 +2168,7 @@ public final class ActivityThread { + ", comp=" + name + ", token=" + token); } - return performLaunchActivity(r); + return performLaunchActivity(r, null); } public final Activity getActivity(IBinder token) { @@ -2159,7 +2218,7 @@ public final class ActivityThread { queueOrSendMessage(H.CLEAN_UP_CONTEXT, cci); } - private final Activity performLaunchActivity(ActivityRecord r) { + private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; @@ -2219,6 +2278,9 @@ public final class ActivityThread { r.lastNonConfigurationInstance, r.lastNonConfigurationChildInstances, config); + if (customIntent != null) { + activity.mIntent = customIntent; + } r.lastNonConfigurationInstance = null; r.lastNonConfigurationChildInstances = null; activity.mStartedActivity = false; @@ -2274,14 +2336,14 @@ public final class ActivityThread { return activity; } - private final void handleLaunchActivity(ActivityRecord r) { + private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); if (localLOGV) Log.v( TAG, "Handling launch of " + r); - Activity a = performLaunchActivity(r); + Activity a = performLaunchActivity(r, customIntent); if (a != null) { handleResumeActivity(r.token, false, r.isForward); @@ -3243,6 +3305,7 @@ public final class ActivityThread { } r.activity.mConfigChangeFlags |= configChanges; + Intent currentIntent = r.activity.mIntent; Bundle savedState = null; if (!r.paused) { @@ -3275,7 +3338,7 @@ public final class ActivityThread { r.state = savedState; } - handleLaunchActivity(r); + handleLaunchActivity(r, currentIntent); } private final void handleRequestThumbnail(IBinder token) { @@ -3412,6 +3475,8 @@ public final class ActivityThread { } mConfiguration.updateFrom(config); DisplayMetrics dm = getDisplayMetricsLocked(true); + DisplayMetrics appDm = new DisplayMetrics(); + appDm.setTo(dm); // set it for java, this also affects newly created Resources if (config.locale != null) { @@ -3431,7 +3496,11 @@ public final class ActivityThread { WeakReference v = it.next(); Resources r = v.get(); if (r != null) { - r.updateConfiguration(config, dm); + // keep the original density based on application cale. + appDm.updateDensity(r.getDisplayMetrics().density); + r.updateConfiguration(config, appDm); + // reset + appDm.setTo(dm); //Log.i(TAG, "Updated app resources " + v.getKey() // + " " + r + ": " + r.getConfiguration()); } else { @@ -3492,6 +3561,9 @@ public final class ActivityThread { int sqliteReleased = SQLiteDatabase.releaseMemory(); EventLog.writeEvent(SQLITE_MEM_RELEASED_EVENT_LOG_TAG, sqliteReleased); } + + // Ask graphics to free up as much as possible (font/image caches) + Canvas.freeCaches(); BinderInternal.forceGc("mem"); } diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 55fce4932e6de74df0d996d708aba50b31d5ff43..bb17dc35b4e098709bf6a86fc079efa881113d0b 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -550,6 +550,19 @@ class ApplicationContext extends Context { } } + /** + * @hide + */ + @Override + public float getApplicationScale() { + if (mPackageInfo != null) { + return mPackageInfo.getApplicationScale(); + } else { + // same as system density + return 1.0f; + } + } + @Override public void setWallpaper(Bitmap bitmap) throws IOException { try { @@ -2008,9 +2021,11 @@ class ApplicationContext extends Context { if (app.packageName.equals("system")) { return mContext.mMainThread.getSystemContext().getResources(); } + ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app); Resources r = mContext.mMainThread.getTopLevelResources( app.uid == Process.myUid() ? app.sourceDir - : app.publicSourceDir); + : app.publicSourceDir, + pi.getApplicationScale()); if (r != null) { return r; } @@ -2295,14 +2310,25 @@ class ApplicationContext extends Context { } @Override - public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags) { + public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags, + String installerPackageName) { try { - mPM.installPackage(packageURI, observer, flags); + mPM.installPackage(packageURI, observer, flags, installerPackageName); } catch (RemoteException e) { // Should never happen! } } + @Override + public String getInstallerPackageName(String packageName) { + try { + return mPM.getInstallerPackageName(packageName); + } catch (RemoteException e) { + // Should never happen! + } + return null; + } + @Override public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) { try { diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 2ac6160cf83eb9a39a9e6bb9aacc8a190d092ae8..56b29c1c941fd2a056638de220b68974faed0053 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -16,7 +16,6 @@ package android.app; -import android.app.ActivityManager.MemoryInfo; import android.content.ComponentName; import android.content.ContentProviderNative; import android.content.IContentProvider; @@ -34,7 +33,6 @@ import android.os.IInterface; import android.os.Parcel; import android.os.Parcelable; import android.os.ParcelFileDescriptor; -import android.text.TextUtils; import android.os.Bundle; import java.util.List; @@ -225,6 +223,8 @@ public interface IActivityManager extends IInterface { public boolean profileControl(String process, boolean start, String path) throws RemoteException; + public boolean shutdown(int timeout) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -370,4 +370,5 @@ public interface IActivityManager extends IInterface { int GET_DEVICE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+83; int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84; int PROFILE_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+85; + int SHUTDOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+86; } diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl index 6c3617ae61184f29a4c68dee0b2e766e1bd585dc..39eb4f1ccbe863438dfceec9fca2d4ce7c3dfb8b 100644 --- a/core/java/android/app/ISearchManager.aidl +++ b/core/java/android/app/ISearchManager.aidl @@ -22,4 +22,5 @@ import android.server.search.SearchableInfo; /** @hide */ interface ISearchManager { SearchableInfo getSearchableInfo(in ComponentName launchActivity, boolean globalSearch); + List getSearchablesInGlobalSearch(); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 51fddb1145cbbd50122aa7479b667419e235e0f9..9834c75c58d4b6b932c567f469427b0b2b4cf6d6 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -34,6 +34,9 @@ import android.widget.RemoteViews; * A class that represents how a persistent notification is to be presented to * the user using the {@link android.app.NotificationManager}. * + *

For a guide to creating notifications, see the + * Creating Status + * Bar Notifications document in the Dev Guide.

*/ public class Notification implements Parcelable { @@ -52,7 +55,8 @@ public class Notification implements Parcelable /** * Use the default notification vibrate. This will ignore any given - * {@link #vibrate}. + * {@link #vibrate}. Using phone vibration requires the + * {@link android.Manifest.permission#VIBRATE VIBRATE} permission. * * @see #defaults */ @@ -149,8 +153,7 @@ public class Notification implements Parcelable /** - * The pattern with which to vibrate. This pattern will repeat if {@link - * #FLAG_INSISTENT} bit is set in the {@link #flags} field. + * The pattern with which to vibrate. * *

* To vibrate the default pattern, see {@link #defaults}. @@ -228,13 +231,8 @@ public class Notification implements Parcelable /** * Bit to be bitwise-ored into the {@link #flags} field that if set, - * the audio and vibration will be repeated until the notification is - * cancelled. - * - *

- * NOTE: This notion will change when we have decided exactly - * what the UI will be. - *

+ * the audio will be repeated until the notification is + * cancelled or the notification window is opened. */ public static final int FLAG_INSISTENT = 0x00000004; diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 1bed706763a1a0c11a1ca803fd1c754643a8a1af..cb660c7fde6f55540ceec1f2a1424d0f2001ec87 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -440,9 +440,13 @@ public final class PendingIntent implements Parcelable { @Override public String toString() { - return "PendingIntent{" - + Integer.toHexString(System.identityHashCode(this)) - + " target " + (mTarget != null ? mTarget.asBinder() : null) + "}"; + StringBuilder sb = new StringBuilder(128); + sb.append("PendingIntent{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(": "); + sb.append(mTarget != null ? mTarget.asBinder() : null); + sb.append('}'); + return sb.toString(); } public int describeContents() { diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index a0cdb63489c72e1e305a1088e2cb73d26843a624..343380cc766e63651b85112700f51baa68dfc49a 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -16,24 +16,24 @@ package android.app; +import static android.app.SuggestionsAdapter.getColumnString; + 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.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.server.search.SearchableInfo; import android.speech.RecognizerIntent; @@ -45,7 +45,9 @@ import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; @@ -53,17 +55,15 @@ import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AutoCompleteTextView; import android.widget.Button; -import android.widget.CursorAdapter; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; -import android.widget.SimpleCursorAdapter; import android.widget.TextView; -import android.widget.WrapperListAdapter; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; -import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.WeakHashMap; import java.util.concurrent.atomic.AtomicLong; /** @@ -75,59 +75,74 @@ import java.util.concurrent.atomic.AtomicLong; public class SearchDialog extends Dialog implements OnItemClickListener, OnItemSelectedListener { // Debugging support - final static String LOG_TAG = "SearchDialog"; - private static final int DBG_LOG_TIMING = 0; - final static int DBG_JAM_THREADING = 0; + private static final boolean DBG = false; + private static final String LOG_TAG = "SearchDialog"; + private static final boolean DBG_LOG_TIMING = false; - // interaction with runtime - IntentFilter mCloseDialogsFilter; - IntentFilter mPackageFilter; - private static final String INSTANCE_KEY_COMPONENT = "comp"; private static final String INSTANCE_KEY_APPDATA = "data"; private static final String INSTANCE_KEY_GLOBALSEARCH = "glob"; private static final String INSTANCE_KEY_DISPLAY_QUERY = "dQry"; private static final String INSTANCE_KEY_DISPLAY_SEL_START = "sel1"; private static final String INSTANCE_KEY_DISPLAY_SEL_END = "sel2"; - private static final String INSTANCE_KEY_USER_QUERY = "uQry"; - private static final String INSTANCE_KEY_SUGGESTION_QUERY = "sQry"; private static final String INSTANCE_KEY_SELECTED_ELEMENT = "slEl"; private static final int INSTANCE_SELECTED_BUTTON = -2; private static final int INSTANCE_SELECTED_QUERY = -1; - + + private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12; + private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7; + + // interaction with runtime + private IntentFilter mCloseDialogsFilter; + private IntentFilter mPackageFilter; + // views & widgets private TextView mBadgeLabel; - private AutoCompleteTextView mSearchTextField; + private ImageView mAppIcon; + private SearchAutoComplete mSearchAutoComplete; private Button mGoButton; private ImageButton mVoiceButton; + private View mSearchPlate; // interaction with searchable application + private SearchableInfo mSearchable; private ComponentName mLaunchComponent; private Bundle mAppSearchData; private boolean mGlobalSearchMode; private Context mActivityContext; - - // interaction with the search manager service - private SearchableInfo mSearchable; - // support for suggestions - private String mUserQuery = null; - private int mUserQuerySelStart; - private int mUserQuerySelEnd; - private boolean mLeaveJammedQueryOnRefocus = false; - private String mPreviousSuggestionQuery = null; - private int mPresetSelection = -1; - private String mSuggestionAction = null; - private Uri mSuggestionData = null; - private String mSuggestionQuery = null; + // Values we store to allow user to toggle between in-app search and global search. + private ComponentName mStoredComponentName; + private Bundle mStoredAppSearchData; + // stack of previous searchables, to support the BACK key after + // SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE. + // The top of the stack (= previous searchable) is the last element of the list, + // since adding and removing is efficient at the end of an ArrayList. + private ArrayList mPreviousComponents; + // For voice searching private Intent mVoiceWebSearchIntent; private Intent mVoiceAppSearchIntent; // support for AutoCompleteTextView suggestions display private SuggestionsAdapter mSuggestionsAdapter; - + + // Whether to rewrite queries when selecting suggestions + // TODO: This is disabled because of problems with persistent selections + // causing non-user-initiated rewrites. + private static final boolean REWRITE_QUERIES = false; + + // The query entered by the user. This is not changed when selecting a suggestion + // that modifies the contents of the text field. But if the user then edits + // the suggestion, the resulting string is saved. + private String mUserQuery; + + // A weak map of drawables we've gotten from other packages, so we don't load them + // more than once. + private final WeakHashMap mOutsideDrawablesCache = + new WeakHashMap(); + /** * Constructor - fires it up and makes it look like the search UI. * @@ -151,27 +166,35 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS setContentView(com.android.internal.R.layout.search_bar); theWindow.setLayout(ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); + // taking up the whole window (even when transparent) is less than ideal, + // but necessary to show the popup window until the window manager supports + // having windows anchored by their parent but not clipped by them. + ViewGroup.LayoutParams.FILL_PARENT); WindowManager.LayoutParams lp = theWindow.getAttributes(); - lp.setTitle("Search Dialog"); - lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE; + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; theWindow.setAttributes(lp); // get the view elements for local access mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge); - mSearchTextField = (AutoCompleteTextView) + mSearchAutoComplete = (SearchAutoComplete) findViewById(com.android.internal.R.id.search_src_text); + mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon); mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn); mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn); + mSearchPlate = findViewById(com.android.internal.R.id.search_plate); // attach listeners - mSearchTextField.addTextChangedListener(mTextWatcher); - mSearchTextField.setOnKeyListener(mTextKeyListener); + mSearchAutoComplete.addTextChangedListener(mTextWatcher); + mSearchAutoComplete.setOnKeyListener(mTextKeyListener); + mSearchAutoComplete.setOnItemClickListener(this); + mSearchAutoComplete.setOnItemSelectedListener(this); mGoButton.setOnClickListener(mGoButtonClickListener); mGoButton.setOnKeyListener(mButtonsKeyListener); mVoiceButton.setOnClickListener(mVoiceButtonClickListener); mVoiceButton.setOnKeyListener(mButtonsKeyListener); + mSearchAutoComplete.setSearchDialog(this); + // pre-hide all the extraneous elements mBadgeLabel.setVisibility(View.GONE); @@ -199,7 +222,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS /** * Set up the search dialog * - * @param Returns true if search dialog launched, false if not + * @return true if search dialog launched, false if not */ public boolean show(String initialQuery, boolean selectInitialQuery, ComponentName componentName, Bundle appSearchData, boolean globalSearch) { @@ -208,75 +231,135 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // in this case, just discard the "show" request return true; } - - // Get searchable info from search manager and use to set up other elements of UI - // Do this first so we can get out quickly if there's nothing to search - ISearchManager sms; - sms = ISearchManager.Stub.asInterface(ServiceManager.getService(Context.SEARCH_SERVICE)); - try { - mSearchable = sms.getSearchableInfo(componentName, globalSearch); - } catch (RemoteException e) { - mSearchable = null; + + // Reset any stored values from last time dialog was shown. + mStoredComponentName = null; + mStoredAppSearchData = null; + + return doShow(initialQuery, selectInitialQuery, componentName, appSearchData, globalSearch); + } + + + /** + * Called in response to a press of the hard search button in + * {@link #onKeyDown(int, KeyEvent)}, this method toggles between in-app + * search and global search when relevant. + * + * If pressed within an in-app search context, this switches the search dialog out to + * global search. If pressed within a global search context that was originally an in-app + * search context, this switches back to the in-app search context. If pressed within a + * global search context that has no original in-app search context (e.g., global search + * from Home), this does nothing. + * + * @return false if we wanted to toggle context but could not do so successfully, true + * in all other cases + */ + private boolean toggleGlobalSearch() { + String currentSearchText = mSearchAutoComplete.getText().toString(); + if (!mGlobalSearchMode) { + mStoredComponentName = mLaunchComponent; + mStoredAppSearchData = mAppSearchData; + return doShow(currentSearchText, false, null, mAppSearchData, true); + } else { + if (mStoredComponentName != null) { + // This means we should toggle *back* to an in-app search context from + // global search. + return doShow(currentSearchText, false, mStoredComponentName, + mStoredAppSearchData, false); + } else { + return true; + } } - if (mSearchable == null) { - // unfortunately, we can't log here. it would be logspam every time the user - // clicks the "search" key on a non-search app + } + + /** + * Does the rest of the work required to show the search dialog. Called by both + * {@link #show(String, boolean, ComponentName, Bundle, boolean)} and + * {@link #toggleGlobalSearch()}. + * + * @return true if search dialog showed, false if not + */ + private boolean doShow(String initialQuery, boolean selectInitialQuery, + ComponentName componentName, Bundle appSearchData, + boolean globalSearch) { + // set up the searchable and show the dialog + if (!show(componentName, appSearchData, globalSearch)) { return false; } - - // OK, we're going to show ourselves - super.show(); - setupSearchableInfo(); + // finally, load the user's initial text (which may trigger suggestions) + setUserQuery(initialQuery); + if (selectInitialQuery) { + mSearchAutoComplete.selectAll(); + } + + return true; + } + + /** + * Sets up the search dialog and shows it. + * + * @return true if search dialog launched + */ + private boolean show(ComponentName componentName, Bundle appSearchData, + boolean globalSearch) { + + if (DBG) { + Log.d(LOG_TAG, "show(" + componentName + ", " + + appSearchData + ", " + globalSearch + ")"); + } + + // Try to get the searchable info for the provided component (or for global search, + // if globalSearch == true). + mSearchable = SearchManager.getSearchableInfo(componentName, globalSearch); + + // If we got back nothing, and it wasn't a request for global search, then try again + // for global search, as we'll try to launch that in lieu of any component-specific search. + if (!globalSearch && mSearchable == null) { + globalSearch = true; + mSearchable = SearchManager.getSearchableInfo(componentName, globalSearch); + + // If we still get back null (i.e., there's not even a searchable info available + // for global search), then really give up. + if (mSearchable == null) { + // Unfortunately, we can't log here. it would be logspam every time the user + // clicks the "search" key on a non-search app. + return false; + } + } mLaunchComponent = componentName; mAppSearchData = appSearchData; - mGlobalSearchMode = globalSearch; - - // receive broadcasts - getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter); - getContext().registerReceiver(mBroadcastReceiver, mPackageFilter); + // Using globalSearch here is just an optimization, just calling + // isDefaultSearchable() should always give the same result. + mGlobalSearchMode = globalSearch || SearchManager.isDefaultSearchable(mSearchable); + mActivityContext = mSearchable.getActivityContext(getContext()); - // configure the autocomplete aspects of the input box - mSearchTextField.setOnItemClickListener(this); - mSearchTextField.setOnItemSelectedListener(this); - - // This conversion is necessary to force a preload of the EditText and thus force - // suggestions to be presented (even for an empty query) - if (initialQuery == null) { - initialQuery = ""; // This forces the preload to happen, triggering suggestions + // show the dialog. this will call onStart(). + if (!isShowing()) { + // First make sure the keyboard is showing (if needed), so that we get the right height + // for the dropdown to respect the IME. + if (getContext().getResources().getConfiguration().hardKeyboardHidden == + Configuration.HARDKEYBOARDHIDDEN_YES) { + InputMethodManager inputManager = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + inputManager.showSoftInputUnchecked(0, null); + } + show(); } - // attach the suggestions adapter, if suggestions are available - // The existence of a suggestions authority is the proxy for "suggestions available here" - if (mSearchable.getSuggestAuthority() == null) { - mSuggestionsAdapter = null; - mSearchTextField.setAdapter(mSuggestionsAdapter); - mSearchTextField.setText(initialQuery); - } else { - mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable, - mSearchTextField); - mSearchTextField.setAdapter(mSuggestionsAdapter); - - // finally, load the user's initial text (which may trigger suggestions) - mSuggestionsAdapter.setNonUserQuery(false); - mSearchTextField.setText(initialQuery); - } + updateUI(); - if (selectInitialQuery) { - mSearchTextField.selectAll(); - } else { - mSearchTextField.setSelection(initialQuery.length()); - } return true; } - - /** - * The default show() for this Dialog is not supported. - */ + @Override - public void show() { - return; + protected void onStart() { + super.onStart(); + + // receive broadcasts + getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter); + getContext().registerReceiver(mBroadcastReceiver, mPackageFilter); } /** @@ -289,6 +372,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS public void onStop() { super.onStop(); + // TODO: Removing the listeners means that they never get called, since + // Dialog.dismissDialog() calls onStop() before sendDismissMessage(). setOnCancelListener(null); setOnDismissListener(null); @@ -299,26 +384,36 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // This is OK - it just means we didn't have any registered } - // close any leftover cursor - if (mSuggestionsAdapter != null) { - mSuggestionsAdapter.changeCursor(null); - } + closeSuggestionsAdapter(); // dump extra memory we're hanging on to mLaunchComponent = null; mAppSearchData = null; mSearchable = null; - mSuggestionAction = null; - mSuggestionData = null; - mSuggestionQuery = null; mActivityContext = null; - mPreviousSuggestionQuery = null; mUserQuery = null; + mPreviousComponents = null; + } + + /** + * Closes and gets rid of the suggestions adapter. + */ + private void closeSuggestionsAdapter() { + // remove the adapter from the autocomplete first, to avoid any updates + // when we drop the cursor + mSearchAutoComplete.setAdapter((SuggestionsAdapter)null); + // close any leftover cursor + if (mSuggestionsAdapter != null) { + mSuggestionsAdapter.changeCursor(null); + } + mSuggestionsAdapter = null; } /** * Save the minimal set of data necessary to recreate the search * + * TODO: go through this and make sure that it saves everything that is needed + * * @return A bundle with the state of the dialog. */ @Override @@ -331,16 +426,14 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS bundle.putBoolean(INSTANCE_KEY_GLOBALSEARCH, mGlobalSearchMode); // UI state - bundle.putString(INSTANCE_KEY_DISPLAY_QUERY, mSearchTextField.getText().toString()); - bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_START, mSearchTextField.getSelectionStart()); - bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_END, mSearchTextField.getSelectionEnd()); - bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery); - bundle.putString(INSTANCE_KEY_SUGGESTION_QUERY, mPreviousSuggestionQuery); + bundle.putString(INSTANCE_KEY_DISPLAY_QUERY, mSearchAutoComplete.getText().toString()); + bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_START, mSearchAutoComplete.getSelectionStart()); + bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_END, mSearchAutoComplete.getSelectionEnd()); int selectedElement = INSTANCE_SELECTED_QUERY; if (mGoButton.isFocused()) { selectedElement = INSTANCE_SELECTED_BUTTON; - } else if (mSearchTextField.isPopupShowing()) { + } else if (mSearchAutoComplete.isPopupShowing()) { selectedElement = 0; // TODO mSearchTextField.getListSelection() // 0..n } bundle.putInt(INSTANCE_KEY_SELECTED_ELEMENT, selectedElement); @@ -350,6 +443,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS /** * Restore the state of the dialog from a previously saved bundle. + * + * TODO: go through this and make sure that it saves everything that is saved * * @param savedInstanceState The state of the dialog previously saved by * {@link #onSaveInstanceState()}. @@ -365,26 +460,17 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS String displayQuery = savedInstanceState.getString(INSTANCE_KEY_DISPLAY_QUERY); int querySelStart = savedInstanceState.getInt(INSTANCE_KEY_DISPLAY_SEL_START, -1); int querySelEnd = savedInstanceState.getInt(INSTANCE_KEY_DISPLAY_SEL_END, -1); - String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY); int selectedElement = savedInstanceState.getInt(INSTANCE_KEY_SELECTED_ELEMENT); - String suggestionQuery = savedInstanceState.getString(INSTANCE_KEY_SUGGESTION_QUERY); // show the dialog. skip any show/hide animation, we want to go fast. // send the text that actually generates the suggestions here; we'll replace the display // text as necessary in a moment. - if (!show(suggestionQuery, false, launchComponent, appSearchData, globalSearch)) { + if (!show(displayQuery, false, launchComponent, appSearchData, globalSearch)) { // for some reason, we couldn't re-instantiate return; } - if (mSuggestionsAdapter != null) { - mSuggestionsAdapter.setNonUserQuery(true); - } - mSearchTextField.setText(displayQuery); - // TODO because the new query is (not) processed in another thread, we can't just - // take away this flag (yet). The better solution here is going to require a new API - // in AutoCompleteTextView which allows us to change the text w/o changing the suggestions. -// mSuggestionsAdapter.setNonUserQuery(false); + mSearchAutoComplete.setText(displayQuery); // clean up the selection state switch (selectedElement) { @@ -395,40 +481,38 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS break; case INSTANCE_SELECTED_QUERY: if (querySelStart >= 0 && querySelEnd >= 0) { - mSearchTextField.requestFocus(); - mSearchTextField.setSelection(querySelStart, querySelEnd); + mSearchAutoComplete.requestFocus(); + mSearchAutoComplete.setSelection(querySelStart, querySelEnd); } break; default: - // defer selecting a list element until suggestion list appears - mPresetSelection = selectedElement; - // TODO mSearchTextField.setListSelection(selectedElement) + // TODO: defer selecting a list element until suggestion list appears +// mSearchAutoComplete.setListSelection(selectedElement) break; } } /** - * Hook for updating layout on a rotation - * + * Called after resources have changed, e.g. after screen rotation or locale change. */ public void onConfigurationChanged(Configuration newConfig) { if (isShowing()) { // Redraw (resources may have changed) updateSearchButton(); + updateSearchAppIcon(); updateSearchBadge(); updateQueryHint(); } } - + /** - * Use SearchableInfo record (from search manager service) to preconfigure the UI in various - * ways. + * Update the UI according to the info in the current value of {@link #mSearchable}. */ - private void setupSearchableInfo() { + private void updateUI() { if (mSearchable != null) { - mActivityContext = mSearchable.getActivityContext(getContext()); - + updateSearchAutoComplete(); updateSearchButton(); + updateSearchAppIcon(); updateSearchBadge(); updateQueryHint(); updateVoiceButton(); @@ -449,24 +533,42 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; } } - mSearchTextField.setInputType(inputType); - mSearchTextField.setImeOptions(mSearchable.getImeOptions()); + mSearchAutoComplete.setInputType(inputType); + mSearchAutoComplete.setImeOptions(mSearchable.getImeOptions()); } } - + /** - * The list of installed packages has just changed. This means that our current context - * may no longer be valid. This would only happen if a package is installed/removed exactly - * when the search bar is open. So for now we're just going to close the search - * bar. - * - * Anything fancier would require some checks to see if the user's context was still valid. - * Which would be messier. + * Updates the auto-complete text view. */ - public void onPackageListChange() { - cancel(); + private void updateSearchAutoComplete() { + // close any existing suggestions adapter + closeSuggestionsAdapter(); + + mSearchAutoComplete.setDropDownAnimationStyle(0); // no animation + mSearchAutoComplete.setThreshold(mSearchable.getSuggestThreshold()); + + if (mGlobalSearchMode) { + mSearchAutoComplete.setDropDownAlwaysVisible(true); // fill space until results come in + mSearchAutoComplete.setDropDownDismissedOnCompletion(false); + mSearchAutoComplete.setDropDownBackgroundResource( + com.android.internal.R.drawable.search_dropdown_background); + } else { + mSearchAutoComplete.setDropDownAlwaysVisible(false); + mSearchAutoComplete.setDropDownDismissedOnCompletion(true); + mSearchAutoComplete.setDropDownBackgroundResource( + com.android.internal.R.drawable.search_dropdown_background_apps); + } + + // attach the suggestions adapter, if suggestions are available + // The existence of a suggestions authority is the proxy for "suggestions available here" + if (mSearchable.getSuggestAuthority() != null) { + mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable, + mOutsideDrawablesCache); + mSearchAutoComplete.setAdapter(mSuggestionsAdapter); + } } - + /** * Update the text in the search button. Note: This is deprecated functionality, for * 1.0 compatibility only. @@ -481,26 +583,56 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS iconLabel = getContext().getResources(). getDrawable(com.android.internal.R.drawable.ic_btn_search); } - mGoButton.setText(textLabel); + mGoButton.setText(textLabel); mGoButton.setCompoundDrawablesWithIntrinsicBounds(iconLabel, null, null, null); } + private void updateSearchAppIcon() { + if (mGlobalSearchMode) { + mAppIcon.setImageResource(0); + mAppIcon.setVisibility(View.GONE); + mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL, + mSearchPlate.getPaddingTop(), + mSearchPlate.getPaddingRight(), + mSearchPlate.getPaddingBottom()); + } else { + PackageManager pm = getContext().getPackageManager(); + Drawable icon = null; + try { + ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0); + icon = pm.getApplicationIcon(info.applicationInfo); + if (DBG) Log.d(LOG_TAG, "Using app-specific icon"); + } catch (NameNotFoundException e) { + icon = pm.getDefaultActivityIcon(); + Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon"); + } + mAppIcon.setImageDrawable(icon); + mAppIcon.setVisibility(View.VISIBLE); + mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL, + mSearchPlate.getPaddingTop(), + mSearchPlate.getPaddingRight(), + mSearchPlate.getPaddingBottom()); + } + } + /** - * Setup the search "Badge" if request by mode flags. + * Setup the search "Badge" if requested by mode flags. */ private void updateSearchBadge() { // assume both hidden int visibility = View.GONE; Drawable icon = null; - String text = null; + CharSequence text = null; // optionally show one or the other. - if (mSearchable.mBadgeIcon) { + if (mSearchable.useBadgeIcon()) { icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId()); visibility = View.VISIBLE; - } else if (mSearchable.mBadgeLabel) { + if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId()); + } else if (mSearchable.useBadgeLabel()) { text = mActivityContext.getResources().getText(mSearchable.getLabelId()).toString(); visibility = View.VISIBLE; + if (DBG) Log.d(LOG_TAG, "Using badge label: " + mSearchable.getLabelId()); } mBadgeLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); @@ -520,7 +652,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS hint = mActivityContext.getString(hintId); } } - mSearchTextField.setHint(hint); + mSearchAutoComplete.setHint(hint); } } @@ -552,59 +684,84 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * Listeners of various types */ + /** + * {@link Dialog#onTouchEvent(MotionEvent)} will cancel the dialog only when the + * touch is outside the window. But the window includes space for the drop-down, + * so we also cancel on taps outside the search bar when the drop-down is not showing. + */ + @Override + public boolean onTouchEvent(MotionEvent event) { + // cancel if the drop-down is not showing and the touch event was outside the search plate + if (!mSearchAutoComplete.isPopupShowing() && isOutOfBounds(mSearchPlate, event)) { + if (DBG) Log.d(LOG_TAG, "Pop-up not showing and outside of search plate."); + cancel(); + return true; + } + // Let Dialog handle events outside the window while the pop-up is showing. + return super.onTouchEvent(event); + } + + private boolean isOutOfBounds(View v, MotionEvent event) { + final int x = (int) event.getX(); + final int y = (int) event.getY(); + final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop(); + return (x < -slop) || (y < -slop) + || (x > (v.getWidth()+slop)) + || (y > (v.getHeight()+slop)); + } + /** * Dialog's OnKeyListener implements various search-specific functionality * * @param keyCode This is the keycode of the typed key, and is the same value as - * found in the KeyEvent parameter. + * found in the KeyEvent parameter. * @param event The complete event record for the typed key * * @return Return true if the event was handled here, or false if not. */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_BACK: - cancel(); + if (DBG) Log.d(LOG_TAG, "onKeyDown(" + keyCode + "," + event + ")"); + + // handle back key to go back to previous searchable, etc. + if (handleBackKey(keyCode, event)) { return true; - case KeyEvent.KEYCODE_SEARCH: - if (TextUtils.getTrimmedLength(mSearchTextField.getText()) != 0) { - launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); - } else { - cancel(); - } + } + + if (keyCode == KeyEvent.KEYCODE_SEARCH) { + // If the search key is pressed, toggle between global and in-app search. If we are + // currently doing global search and there is no in-app search context to toggle to, + // just don't do anything. + return toggleGlobalSearch(); + } + + // if it's an action specified by the searchable activity, launch the + // entered query with the action key + SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); + if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { + launchQuerySearch(keyCode, actionKey.getQueryActionMsg()); return true; - default: - SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); - if ((actionKey != null) && (actionKey.mQueryActionMsg != null)) { - launchQuerySearch(keyCode, actionKey.mQueryActionMsg); - return true; - } - break; } + return false; } - + /** * Callback to watch the textedit field for empty/non-empty */ private TextWatcher mTextWatcher = new TextWatcher() { - public void beforeTextChanged(CharSequence s, int start, int - before, int after) { } + public void beforeTextChanged(CharSequence s, int start, int before, int after) { } public void onTextChanged(CharSequence s, int start, int before, int after) { - if (DBG_LOG_TIMING == 1) { + if (DBG_LOG_TIMING) { dbgLogTiming("onTextChanged()"); } updateWidgetState(); - // Only do suggestions if actually typed by user - if ((mSuggestionsAdapter != null) && !mSuggestionsAdapter.getNonUserQuery()) { - mPreviousSuggestionQuery = s.toString(); - mUserQuery = mSearchTextField.getText().toString(); - mUserQuerySelStart = mSearchTextField.getSelectionStart(); - mUserQuerySelEnd = mSearchTextField.getSelectionEnd(); + if (!mSearchAutoComplete.isPerformingCompletion()) { + // The user changed the query, remember it. + mUserQuery = s == null ? "" : s.toString(); } } @@ -616,64 +773,34 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ private void updateWidgetState() { // enable the button if we have one or more non-space characters - boolean enabled = - TextUtils.getTrimmedLength(mSearchTextField.getText()) != 0; - + boolean enabled = !mSearchAutoComplete.isEmpty(); mGoButton.setEnabled(enabled); mGoButton.setFocusable(enabled); } - private final static String[] ONE_LINE_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1 }; - private final static String[] ONE_LINE_ICONS_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1, - SearchManager.SUGGEST_COLUMN_ICON_1, - SearchManager.SUGGEST_COLUMN_ICON_2}; - private final static String[] TWO_LINE_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1, - SearchManager.SUGGEST_COLUMN_TEXT_2 }; - private final static String[] TWO_LINE_ICONS_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1, - SearchManager.SUGGEST_COLUMN_TEXT_2, - SearchManager.SUGGEST_COLUMN_ICON_1, - SearchManager.SUGGEST_COLUMN_ICON_2 }; - - private final static int[] ONE_LINE_TO = {com.android.internal.R.id.text1}; - private final static int[] ONE_LINE_ICONS_TO = {com.android.internal.R.id.text1, - com.android.internal.R.id.icon1, - com.android.internal.R.id.icon2}; - private final static int[] TWO_LINE_TO = {com.android.internal.R.id.text1, - com.android.internal.R.id.text2}; - private final static int[] TWO_LINE_ICONS_TO = {com.android.internal.R.id.text1, - com.android.internal.R.id.text2, - com.android.internal.R.id.icon1, - com.android.internal.R.id.icon2}; - - /** - * Safely retrieve the suggestions cursor adapter from the ListView - * - * @param adapterView The ListView containing our adapter - * @result The CursorAdapter that we installed, or null if not set - */ - private static CursorAdapter getSuggestionsAdapter(AdapterView adapterView) { - CursorAdapter result = null; - if (adapterView != null) { - Object ad = adapterView.getAdapter(); - if (ad instanceof CursorAdapter) { - result = (CursorAdapter) ad; - } else if (ad instanceof WrapperListAdapter) { - result = (CursorAdapter) ((WrapperListAdapter)ad).getWrappedAdapter(); - } - } - return result; - } - /** * React to typing in the GO search button by refocusing to EditText. * Continue typing the query. */ 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) { - return refocusingKeyListener(v, keyCode, event); + // guard against possible race conditions + if (mSearchable == null) { + return false; } + + if (!event.isSystem() && + (keyCode != KeyEvent.KEYCODE_DPAD_UP) && + (keyCode != KeyEvent.KEYCODE_DPAD_DOWN) && + (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) && + (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) && + (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) { + // restore focus and give key to EditText ... + if (mSearchAutoComplete.requestFocus()) { + return mSearchAutoComplete.dispatchKeyEvent(event); + } + } + return false; } }; @@ -683,10 +810,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ View.OnClickListener mGoButtonClickListener = new View.OnClickListener() { public void onClick(View v) { - // also guard against possible race conditions (late arrival after dismiss) - if (mSearchable != null) { - launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); + // guard against possible race conditions + if (mSearchable == null) { + return; } + launchQuerySearch(); } }; @@ -695,14 +823,16 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ View.OnClickListener mVoiceButtonClickListener = new View.OnClickListener() { public void onClick(View v) { + // guard against possible race conditions + if (mSearchable == null) { + return; + } try { if (mSearchable.getVoiceSearchLaunchWebSearch()) { getContext().startActivity(mVoiceWebSearchIntent); - dismiss(); } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent); getContext().startActivity(appSearchIntent); - dismiss(); } } catch (ActivityNotFoundException e) { // Should not happen, since we check the availability of @@ -724,7 +854,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // in the voice search system. We have to keep the bundle separate, // because it becomes immutable once it enters the PendingIntent Intent queryIntent = new Intent(Intent.ACTION_SEARCH); - queryIntent.setComponent(mSearchable.mSearchActivity); + queryIntent.setComponent(mSearchable.getSearchActivity()); PendingIntent pending = PendingIntent.getActivity( getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT); @@ -778,136 +908,56 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ View.OnKeyListener mTextKeyListener = new View.OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - cancel(); - return true; - } - // also guard against possible race conditions (late arrival after dismiss) - if (mSearchable != null && - TextUtils.getTrimmedLength(mSearchTextField.getText()) > 0) { - if (DBG_LOG_TIMING == 1) { - dbgLogTiming("doTextKey()"); - } - // dispatch "typing in the list" first - if (mSearchTextField.isPopupShowing() && - mSearchTextField.getListSelection() != ListView.INVALID_POSITION) { - return onSuggestionsKey(v, keyCode, event); - } - // otherwise, dispatch an "edit view" key - switch (keyCode) { - case KeyEvent.KEYCODE_ENTER: - if (event.getAction() == KeyEvent.ACTION_UP) { - v.cancelLongPress(); - launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); - return true; - } - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - // capture the EditText state, so we can restore the user entry later - mUserQuery = mSearchTextField.getText().toString(); - mUserQuerySelStart = mSearchTextField.getSelectionStart(); - mUserQuerySelEnd = mSearchTextField.getSelectionEnd(); - // pass through - we're just watching here - break; - default: - if (event.getAction() == KeyEvent.ACTION_DOWN) { - SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); - if ((actionKey != null) && (actionKey.mQueryActionMsg != null)) { - launchQuerySearch(keyCode, actionKey.mQueryActionMsg); - return true; - } - } - break; - } + // guard against possible race conditions + if (mSearchable == null) { + return false; } - return false; - } - }; - - /** - * React to the user typing while the suggestions are focused. First, check for action - * keys. If not handled, try refocusing regular characters into the EditText. In this case, - * replace the query text (start typing fresh text). - */ - private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) { - boolean handled = false; - // also guard against possible race conditions (late arrival after dismiss) - if (mSearchable != null) { - handled = doSuggestionsKey(v, keyCode, event); - } - return handled; - } - - /** - * Per UI design, we're going to "steer" any typed keystrokes back into the EditText - * box, even if the user has navigated the focus to the dropdown or to the GO button. - * - * @param v The view into which the keystroke was typed - * @param keyCode keyCode of entered key - * @param event Full KeyEvent record of entered key - */ - private boolean refocusingKeyListener(View v, int keyCode, KeyEvent event) { - boolean handled = false; - if (!event.isSystem() && - (keyCode != KeyEvent.KEYCODE_DPAD_UP) && - (keyCode != KeyEvent.KEYCODE_DPAD_DOWN) && - (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) && - (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) && - (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) { - // restore focus and give key to EditText ... - // but don't replace the user's query - mLeaveJammedQueryOnRefocus = true; - if (mSearchTextField.requestFocus()) { - handled = mSearchTextField.dispatchKeyEvent(event); + if (DBG_LOG_TIMING) dbgLogTiming("doTextKey()"); + if (DBG) { + Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event + + "), selection: " + mSearchAutoComplete.getListSelection()); } - mLeaveJammedQueryOnRefocus = false; - } - return handled; - } - - /** - * Update query text based on transitions in and out of suggestions list. - */ - /* - * TODO - figure out if this logic is required for the autocomplete text view version - - OnFocusChangeListener mSuggestFocusListener = new OnFocusChangeListener() { - public void onFocusChange(View v, boolean hasFocus) { - // also guard against possible race conditions (late arrival after dismiss) - if (mSearchable == null) { - return; + + // If a suggestion is selected, handle enter, search key, and action keys + // as presses on the selected suggestion + if (mSearchAutoComplete.isPopupShowing() && + mSearchAutoComplete.getListSelection() != ListView.INVALID_POSITION) { + return onSuggestionsKey(v, keyCode, event); } - // Update query text based on navigation in to/out of the suggestions list - if (hasFocus) { - // Entering the list view - record selection point from user's query - mUserQuery = mSearchTextField.getText().toString(); - mUserQuerySelStart = mSearchTextField.getSelectionStart(); - mUserQuerySelEnd = mSearchTextField.getSelectionEnd(); - // then update the query to match the entered selection - jamSuggestionQuery(true, mSuggestionsList, - mSuggestionsList.getSelectedItemPosition()); - } else { - // Exiting the list view - - if (mSuggestionsList.getSelectedItemPosition() < 0) { - // Direct exit - Leave new suggestion in place (do nothing) - } else { - // Navigation exit - restore user's query text - if (!mLeaveJammedQueryOnRefocus) { - jamSuggestionQuery(false, null, -1); + + // If there is text in the query box, handle enter, and action keys + // The search key is handled by the dialog's onKeyDown(). + if (!mSearchAutoComplete.isEmpty()) { + if (keyCode == KeyEvent.KEYCODE_ENTER + && event.getAction() == KeyEvent.ACTION_UP) { + v.cancelLongPress(); + launchQuerySearch(); + return true; + } + if (event.getAction() == KeyEvent.ACTION_DOWN) { + SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); + if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { + launchQuerySearch(keyCode, actionKey.getQueryActionMsg()); + return true; } } } - + return false; } }; - */ - + /** - * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that - * we should close ourselves immediately, in order to allow a higher-priority UI to take over + * When the ACTION_CLOSE_SYSTEM_DIALOGS intent is received, we should close ourselves + * immediately, in order to allow a higher-priority UI to take over * (e.g. phone call received). + * + * When a package is added, removed or changed, our current context + * may no longer be valid. This would only happen if a package is installed/removed exactly + * when the search bar is open. So for now we're just going to close the search + * bar. + * Anything fancier would require some checks to see if the user's context was still valid. + * Which would be messier. */ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -918,7 +968,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } else if (Intent.ACTION_PACKAGE_ADDED.equals(action) || Intent.ACTION_PACKAGE_REMOVED.equals(action) || Intent.ACTION_PACKAGE_CHANGED.equals(action)) { - onPackageListChange(); + cancel(); } } }; @@ -938,58 +988,45 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } /** - * Various ways to launch searches + * React to the user typing while in the suggestions list. First, check for action + * keys. If not handled, try refocusing regular characters into the EditText. */ - - /** - * React to the user clicking the "GO" button. Hide the UI and launch a search. - * - * @param actionKey Pass a keycode if the launch was triggered by an action key. Pass - * KeyEvent.KEYCODE_UNKNOWN for no actionKey code. - * @param actionMsg Pass the suggestion-provided message if the launch was triggered by an - * action key. Pass null for no actionKey message. - */ - private void launchQuerySearch(int actionKey, final String actionMsg) { - final String query = mSearchTextField.getText().toString(); - final Bundle appData = mAppSearchData; - final SearchableInfo si = mSearchable; // cache briefly (dismiss() nulls it) - dismiss(); - sendLaunchIntent(Intent.ACTION_SEARCH, null, query, appData, actionKey, actionMsg, si); - } - - /** - * React to the user typing an action key while in the suggestions list - */ - private boolean doSuggestionsKey(View v, int keyCode, KeyEvent event) { - // Exit early in case of race condition + private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) { + // guard against possible race conditions (late arrival after dismiss) + if (mSearchable == null) { + return false; + } if (mSuggestionsAdapter == null) { return false; } if (event.getAction() == KeyEvent.ACTION_DOWN) { - if (DBG_LOG_TIMING == 1) { - dbgLogTiming("doSuggestionsKey()"); + if (DBG_LOG_TIMING) { + dbgLogTiming("onSuggestionsKey()"); } // First, check for enter or search (both of which we'll treat as a "click") if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { - int position = mSearchTextField.getListSelection(); - return launchSuggestion(mSuggestionsAdapter, position); + int position = mSearchAutoComplete.getListSelection(); + return launchSuggestion(position); } // Next, check for left/right moves, which we use to "return" the user to the edit view if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { - // give "focus" to text editor, but don't restore the user's original query + // give "focus" to text editor, with cursor at the beginning if + // left key, at end if right key + // TODO: Reverse left/right for right-to-left languages, e.g. Arabic int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? - 0 : mSearchTextField.length(); - mSearchTextField.setSelection(selPoint); - mSearchTextField.setListSelection(0); - mSearchTextField.clearListSelection(); + 0 : mSearchAutoComplete.length(); + mSearchAutoComplete.setSelection(selPoint); + mSearchAutoComplete.setListSelection(0); + mSearchAutoComplete.clearListSelection(); return true; } // Next, check for an "up and out" move - if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mSearchTextField.getListSelection()) { - jamSuggestionQuery(false, null, -1); + if (keyCode == KeyEvent.KEYCODE_DPAD_UP + && 0 == mSearchAutoComplete.getListSelection()) { + restoreUserQuery(); // let ACTV complete the move return false; } @@ -997,160 +1034,196 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // Next, check for an "action key" SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); if ((actionKey != null) && - ((actionKey.mSuggestActionMsg != null) || - (actionKey.mSuggestActionMsgColumn != null))) { - // launch suggestion using action key column - int position = mSearchTextField.getListSelection(); - if (position >= 0) { + ((actionKey.getSuggestActionMsg() != null) || + (actionKey.getSuggestActionMsgColumn() != null))) { + // launch suggestion using action key column + int position = mSearchAutoComplete.getListSelection(); + if (position != ListView.INVALID_POSITION) { Cursor c = mSuggestionsAdapter.getCursor(); if (c.moveToPosition(position)) { final String actionMsg = getActionKeyMessage(c, actionKey); if (actionMsg != null && (actionMsg.length() > 0)) { - // shut down search bar and launch the activity - // cache everything we need because dismiss releases mems - setupSuggestionIntent(c, mSearchable); - final String query = mSearchTextField.getText().toString(); - final Bundle appData = mAppSearchData; - SearchableInfo si = mSearchable; - String suggestionAction = mSuggestionAction; - Uri suggestionData = mSuggestionData; - String suggestionQuery = mSuggestionQuery; - dismiss(); - sendLaunchIntent(suggestionAction, suggestionData, - suggestionQuery, appData, - keyCode, actionMsg, si); - return true; + return launchSuggestion(position, keyCode, actionMsg); } } } } } return false; - } + } + + /** + * Launch a search for the text in the query text field. + */ + protected void launchQuerySearch() { + launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); + } /** - * Set or reset the user query to follow the selections in the suggestions + * Launch a search for the text in the query text field. + * + * @param actionKey The key code of the action key that was pressed, + * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. + * @param actionMsg The message for the action key that was pressed, + * or null if none. + */ + protected void launchQuerySearch(int actionKey, String actionMsg) { + String query = mSearchAutoComplete.getText().toString(); + Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null, + actionKey, actionMsg); + launchIntent(intent); + } + + /** + * Launches an intent based on a suggestion. * - * @param jamQuery True means to set the query, false means to reset it to the user's choice + * @param position The index of the suggestion to create the intent from. + * @return true if a successful launch, false if could not (e.g. bad position). */ - private void jamSuggestionQuery(boolean jamQuery, AdapterView parent, int position) { - // quick check against race conditions - if (mSearchable == null) { + protected boolean launchSuggestion(int position) { + return launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null); + } + + /** + * Launches an intent based on a suggestion. + * + * @param position The index of the suggestion to create the intent from. + * @param actionKey The key code of the action key that was pressed, + * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. + * @param actionMsg The message for the action key that was pressed, + * or null if none. + * @return true if a successful launch, false if could not (e.g. bad position). + */ + protected boolean launchSuggestion(int position, int actionKey, String actionMsg) { + Cursor c = mSuggestionsAdapter.getCursor(); + if ((c != null) && c.moveToPosition(position)) { + Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg); + launchIntent(intent); + return true; + } + return false; + } + + /** + * Launches an intent. Also dismisses the search dialog if not in global search mode. + */ + private void launchIntent(Intent intent) { + if (intent == null) { return; } - - mSuggestionsAdapter.setNonUserQuery(true); // disables any suggestions processing - if (jamQuery) { - CursorAdapter ca = getSuggestionsAdapter(parent); - Cursor c = ca.getCursor(); - if (c.moveToPosition(position)) { - setupSuggestionIntent(c, mSearchable); - String jamText = null; - - // Simple heuristic for selecting text with which to rewrite the query. - if (mSuggestionQuery != null) { - jamText = mSuggestionQuery; - } else if (mSearchable.mQueryRewriteFromData && (mSuggestionData != null)) { - jamText = mSuggestionData.toString(); - } else if (mSearchable.mQueryRewriteFromText) { - try { - int column = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1); - jamText = c.getString(column); - } catch (RuntimeException e) { - // no work here, jamText is null - } - } - if (jamText != null) { - mSearchTextField.setText(jamText); - /* mSearchTextField.selectAll(); */ // this didn't work anyway in the old UI - // TODO this is only needed in the model where we have a selection in the ACTV - // and in the dropdown at the same time. - mSearchTextField.setSelection(jamText.length()); - } - } - } else { - // reset user query - mSearchTextField.setText(mUserQuery); - try { - mSearchTextField.setSelection(mUserQuerySelStart, mUserQuerySelEnd); - } catch (IndexOutOfBoundsException e) { - // In case of error, just select all - Log.e(LOG_TAG, "Caught IndexOutOfBoundsException while setting selection. " + - "start=" + mUserQuerySelStart + " end=" + mUserQuerySelEnd + - " text=\"" + mUserQuery + "\""); - mSearchTextField.selectAll(); - } + if (handleSpecialIntent(intent)){ + return; } - // TODO because the new query is (not) processed in another thread, we can't just - // take away this flag (yet). The better solution here is going to require a new API - // in AutoCompleteTextView which allows us to change the text w/o changing the suggestions. -// mSuggestionsAdapter.setNonUserQuery(false); + if (!mGlobalSearchMode) { + dismiss(); + } + getContext().startActivity(intent); } - + /** - * Assemble a search intent and send it. - * - * @param action The intent to send, typically Intent.ACTION_SEARCH - * @param data The data for the intent - * @param query The user text entered (so far) - * @param appData The app data bundle (if supplied) - * @param actionKey If the intent was triggered by an action key, e.g. KEYCODE_CALL, it will - * be sent here. Pass KeyEvent.KEYCODE_UNKNOWN for no actionKey code. - * @param actionMsg If the intent was triggered by an action key, e.g. KEYCODE_CALL, the - * corresponding tag message will be sent here. Pass null for no actionKey message. - * @param si Reference to the current SearchableInfo. Passed here so it can be used even after - * we've called dismiss(), which attempts to null mSearchable. + * Handles the special intent actions declared in {@link SearchManager}. + * + * @return true if the intent was handled. */ - private void sendLaunchIntent(final String action, final Uri data, final String query, - final Bundle appData, int actionKey, final String actionMsg, final SearchableInfo si) { - Intent launcher = new Intent(action); - - if (query != null) { - launcher.putExtra(SearchManager.QUERY, query); + private boolean handleSpecialIntent(Intent intent) { + String action = intent.getAction(); + if (SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.equals(action)) { + handleChangeSourceIntent(intent); + return true; + } else if (SearchManager.INTENT_ACTION_CURSOR_RESPOND.equals(action)) { + handleCursorRespondIntent(intent); + return true; } - - if (data != null) { - launcher.setData(data); + return false; + } + + /** + * Handles SearchManager#INTENT_ACTION_CHANGE_SOURCE. + */ + private void handleChangeSourceIntent(Intent intent) { + Uri dataUri = intent.getData(); + if (dataUri == null) { + Log.w(LOG_TAG, "SearchManager.INTENT_ACTION_CHANGE_SOURCE without intent data."); + return; } - - if (appData != null) { - launcher.putExtra(SearchManager.APP_DATA, appData); + ComponentName componentName = ComponentName.unflattenFromString(dataUri.toString()); + if (componentName == null) { + Log.w(LOG_TAG, "Invalid ComponentName: " + dataUri); + return; } - - // add launch info (action key, etc.) - if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { - launcher.putExtra(SearchManager.ACTION_KEY, actionKey); - launcher.putExtra(SearchManager.ACTION_MSG, actionMsg); + if (DBG) Log.d(LOG_TAG, "Switching to " + componentName); + + ComponentName previous = mLaunchComponent; + if (!show(componentName, mAppSearchData, false)) { + Log.w(LOG_TAG, "Failed to switch to source " + componentName); + return; } + pushPreviousComponent(previous); - // attempt to enforce security requirement (no 3rd-party intents) - launcher.setComponent(si.mSearchActivity); - - getContext().startActivity(launcher); + String query = intent.getStringExtra(SearchManager.QUERY); + setUserQuery(query); } - + /** - * Shared code for launching a query from a suggestion. - * @param ca The cursor adapter containing the suggestions - * @param position The suggestion we'll be launching from - * @return true if a successful launch, false if could not (e.g. bad position) + * Handles {@link SearchManager#INTENT_ACTION_CURSOR_RESPOND}. */ - private boolean launchSuggestion(CursorAdapter ca, int position) { - Cursor c = ca.getCursor(); - if ((c != null) && c.moveToPosition(position)) { - setupSuggestionIntent(c, mSearchable); - - final Bundle appData = mAppSearchData; - SearchableInfo si = mSearchable; - String suggestionAction = mSuggestionAction; - Uri suggestionData = mSuggestionData; - String suggestionQuery = mSuggestionQuery; - dismiss(); - sendLaunchIntent(suggestionAction, suggestionData, suggestionQuery, appData, - KeyEvent.KEYCODE_UNKNOWN, null, si); - return true; + private void handleCursorRespondIntent(Intent intent) { + Cursor c = mSuggestionsAdapter.getCursor(); + if (c != null) { + c.respond(intent.getExtras()); } - return false; + } + + /** + * Saves the previous component that was searched, so that we can go + * back to it. + */ + private void pushPreviousComponent(ComponentName componentName) { + if (mPreviousComponents == null) { + mPreviousComponents = new ArrayList(); + } + mPreviousComponents.add(componentName); + } + + /** + * Pops the previous component off the stack and returns it. + * + * @return The component name, or null if there was + * no previous component. + */ + private ComponentName popPreviousComponent() { + if (mPreviousComponents == null) { + return null; + } + int size = mPreviousComponents.size(); + if (size == 0) { + return null; + } + return mPreviousComponents.remove(size - 1); + } + + /** + * Goes back to the previous component that was searched, if any. + * + * @return true if there was a previous component that we could go back to. + */ + private boolean backToPreviousComponent() { + ComponentName previous = popPreviousComponent(); + if (previous == null) { + return false; + } + if (!show(previous, mAppSearchData, false)) { + Log.w(LOG_TAG, "Failed to switch to source " + previous); + return false; + } + + // must touch text to trigger suggestions + // TODO: should this be the text as it was when the user left + // the source that we are now going back to? + String query = mSearchAutoComplete.getText().toString(); + setUserQuery(query); + + return true; } /** @@ -1159,62 +1232,43 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * and/or falling back to the XML for defaults; It also creates REST style Uri data when * the suggestion includes a data id. * - * NOTE: Return values are in member variables mSuggestionAction & mSuggestionData. - * * @param c The suggestions cursor, moved to the row of the user's selection - * @param si The searchable activity's info record + * @param actionKey The key code of the action key that was pressed, + * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. + * @param actionMsg The message for the action key that was pressed, + * or null if none. + * @return An intent for the suggestion at the cursor's position. */ - void setupSuggestionIntent(Cursor c, SearchableInfo si) { + private Intent createIntentFromSuggestion(Cursor c, int actionKey, String actionMsg) { try { // use specific action if supplied, or default action if supplied, or fixed default - mSuggestionAction = null; - int mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_ACTION); - if (mColumn >= 0) { - final String action = c.getString(mColumn); - if (action != null) { - mSuggestionAction = action; - } - } - if (mSuggestionAction == null) { - mSuggestionAction = si.getSuggestIntentAction(); + String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION); + if (action == null) { + action = mSearchable.getSuggestIntentAction(); } - if (mSuggestionAction == null) { - mSuggestionAction = Intent.ACTION_SEARCH; + if (action == null) { + action = Intent.ACTION_SEARCH; } // use specific data if supplied, or default data if supplied - String data = null; - mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_DATA); - if (mColumn >= 0) { - final String rowData = c.getString(mColumn); - if (rowData != null) { - data = rowData; - } - } + String data = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA); if (data == null) { - data = si.getSuggestIntentData(); + data = mSearchable.getSuggestIntentData(); } - // then, if an ID was provided, append it. if (data != null) { - mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); - if (mColumn >= 0) { - final String id = c.getString(mColumn); - if (id != null) { - data = data + "/" + Uri.encode(id); - } + String id = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); + if (id != null) { + data = data + "/" + Uri.encode(id); } } - mSuggestionData = (data == null) ? null : Uri.parse(data); + Uri dataUri = (data == null) ? null : Uri.parse(data); + + String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); - mSuggestionQuery = null; - mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY); - if (mColumn >= 0) { - final String query = c.getString(mColumn); - if (query != null) { - mSuggestionQuery = query; - } - } + String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY); + + return createIntent(action, dataUri, query, extraData, actionKey, actionMsg); } catch (RuntimeException e ) { int rowNum; try { // be really paranoid now @@ -1224,7 +1278,46 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } Log.w(LOG_TAG, "Search Suggestions cursor at row " + rowNum + " returned exception" + e.toString()); + return null; + } + } + + /** + * Constructs an intent from the given information and the search dialog state. + * + * @param action Intent action. + * @param data Intent data, or null. + * @param query Intent query, or null. + * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or null. + * @param actionKey The key code of the action key that was pressed, + * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. + * @param actionMsg The message for the action key that was pressed, + * or null if none. + * @return The intent. + */ + private Intent createIntent(String action, Uri data, String query, String extraData, + int actionKey, String actionMsg) { + // Now build the Intent + Intent intent = new Intent(action); + if (data != null) { + intent.setData(data); + } + if (query != null) { + intent.putExtra(SearchManager.QUERY, query); + } + if (extraData != null) { + intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); + } + if (mAppSearchData != null) { + intent.putExtra(SearchManager.APP_DATA, mAppSearchData); + } + if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { + intent.putExtra(SearchManager.ACTION_KEY, actionKey); + intent.putExtra(SearchManager.ACTION_MSG, actionMsg); } + // attempt to enforce security requirement (no 3rd-party intents) + intent.setComponent(mSearchable.getSearchActivity()); + return intent; } /** @@ -1236,364 +1329,195 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * * @return Returns a string, or null if no action key message for this suggestion */ - private String getActionKeyMessage(Cursor c, final SearchableInfo.ActionKeyInfo actionKey) { + private static String getActionKeyMessage(Cursor c, SearchableInfo.ActionKeyInfo actionKey) { String result = null; // check first in the cursor data, for a suggestion-specific message - final String column = actionKey.mSuggestActionMsgColumn; + final String column = actionKey.getSuggestActionMsgColumn(); if (column != null) { - try { - int colId = c.getColumnIndexOrThrow(column); - result = c.getString(colId); - } catch (RuntimeException e) { - // OK - result is already null - } + result = SuggestionsAdapter.getColumnString(c, column); } // If the cursor didn't give us a message, see if there's a single message defined // for the actionkey (for all suggestions) if (result == null) { - result = actionKey.mSuggestActionMsg; + result = actionKey.getSuggestActionMsg(); } return result; } /** - * Local subclass for AutoCompleteTextView - * - * This exists entirely to override the threshold method. Otherwise we just use the class - * as-is. + * Local subclass for AutoCompleteTextView. */ public static class SearchAutoComplete extends AutoCompleteTextView { + private int mThreshold; + private SearchDialog mSearchDialog; + public SearchAutoComplete(Context context) { - super(null); + super(context); + mThreshold = getThreshold(); } public SearchAutoComplete(Context context, AttributeSet attrs) { super(context, attrs); + mThreshold = getThreshold(); } public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + mThreshold = getThreshold(); } - - /** - * We never allow ACTV to automatically replace the text, since we use "jamSuggestionQuery" - * to do that. There's no point in letting ACTV do this here, because in the search UI, - * as soon as we click a suggestion, we're going to start shutting things down. - */ - @Override - public void replaceText(CharSequence text) { + + private void setSearchDialog(SearchDialog searchDialog) { + mSearchDialog = searchDialog; } - /** - * We always return true, so that the effective threshold is "zero". This allows us - * to provide "null" suggestions such as "just show me some recent entries". - */ @Override - public boolean enoughToFilter() { - return true; + public void setThreshold(int threshold) { + super.setThreshold(threshold); + mThreshold = threshold; } - } - - /** - * Support for AutoCompleteTextView-based suggestions - */ - /** - * This class provides the filtering-based interface to suggestions providers. - * It is hardwired in a couple of places to support GoogleSearch - for example, it supports - * two-line suggestions, but it does not support icons. - */ - private static class SuggestionsAdapter extends SimpleCursorAdapter { - private final String TAG = "SuggestionsAdapter"; - - SearchableInfo mSearchable; - private Resources mProviderResources; - - // These private variables are shared by the filter thread and must be protected - private WeakReference mRecentCursor = new WeakReference(null); - private boolean mNonUserQuery = false; - private AutoCompleteTextView mParentView; - public SuggestionsAdapter(Context context, SearchableInfo searchable, - AutoCompleteTextView actv) { - super(context, -1, null, null, null); - mSearchable = searchable; - mParentView = actv; - - // set up provider resources (gives us icons, etc.) - Context activityContext = mSearchable.getActivityContext(mContext); - Context providerContext = mSearchable.getProviderContext(mContext, activityContext); - mProviderResources = providerContext.getResources(); - } - /** - * Set this field (temporarily!) to disable suggestions updating. This allows us - * to change the string in the text view without changing the suggestions list. + * Returns true if the text field is empty, or contains only whitespace. */ - public void setNonUserQuery(boolean nonUserQuery) { - synchronized (this) { - mNonUserQuery = nonUserQuery; - } + private boolean isEmpty() { + return TextUtils.getTrimmedLength(getText()) == 0; } - public boolean getNonUserQuery() { - synchronized (this) { - return mNonUserQuery; - } - } - /** - * Use the search suggestions provider to obtain a live cursor. This will be called - * in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions). - * The results will be processed in the UI thread and changeCursor() will be called. - * - * In order to provide the Search Mgr functionality of seeing your query change as you - * scroll through the list, we have to be able to jam new text into the string without - * retriggering the suggestions. We do that here via the "nonUserQuery" flag. In that - * case we simply return the existing cursor. - * - * TODO: Dianne suggests that this should simply be promoted into an AutoCompleteTextView - * behavior (perhaps optionally). - * - * TODO: The "nonuserquery" logic has a race condition because it happens in another thread. - * This also needs to be fixed. + * Clears the entered text. */ - @Override - public Cursor runQueryOnBackgroundThread(CharSequence constraint) { - String query = (constraint == null) ? "" : constraint.toString(); - Cursor c = null; - synchronized (this) { - if (mNonUserQuery) { - c = mRecentCursor.get(); - mNonUserQuery = false; - } - } - if (c == null) { - c = getSuggestions(mSearchable, query); - synchronized (this) { - mRecentCursor = new WeakReference(c); - } - } - return c; + private void clear() { + setText(""); } /** - * Overriding changeCursor() allows us to change not only the cursor, but by sampling - * the cursor's columns, the actual display characteristics of the list. + * We override this method to avoid replacing the query box text + * when a suggestion is clicked. */ @Override - public void changeCursor(Cursor c) { - - // first, check for various conditions that disqualify this cursor - if ((c == null) || (c.getCount() == 0)) { - // no cursor, or cursor with no data - changeCursorAndColumns(null, null, null); - if (c != null) { - c.close(); - } - return; - } - - // check cursor before trying to create list views from it - int colId = c.getColumnIndex("_id"); - int col1 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); - int col2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); - int colIc1 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); - int colIc2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); - - boolean minimal = (colId >= 0) && (col1 >= 0); - boolean hasIcons = (colIc1 >= 0) && (colIc2 >= 0); - boolean has2Lines = col2 >= 0; - - if (minimal) { - int layout; - String[] from; - int[] to; - - if (hasIcons) { - if (has2Lines) { - layout = com.android.internal.R.layout.search_dropdown_item_icons_2line; - from = TWO_LINE_ICONS_FROM; - to = TWO_LINE_ICONS_TO; - } else { - layout = com.android.internal.R.layout.search_dropdown_item_icons_1line; - from = ONE_LINE_ICONS_FROM; - to = ONE_LINE_ICONS_TO; - } - } else { - if (has2Lines) { - layout = com.android.internal.R.layout.search_dropdown_item_2line; - from = TWO_LINE_FROM; - to = TWO_LINE_TO; - } else { - layout = com.android.internal.R.layout.search_dropdown_item_1line; - from = ONE_LINE_FROM; - to = ONE_LINE_TO; - } - } - // Force the underlying ListView to discard and reload all layouts - // (Note, this should be optimized for cases where layout/cursor remain same) - mParentView.resetListAndClearViews(); - // Now actually set up the cursor, columns, and the list view - changeCursorAndColumns(c, from, to); - setViewResource(layout); - } else { - // Provide some help for developers instead of just silently discarding - Log.w(LOG_TAG, "Suggestions cursor discarded due to missing required columns."); - changeCursorAndColumns(null, null, null); - c.close(); - } - if ((colIc1 >= 0) != (colIc2 >= 0)) { - Log.w(LOG_TAG, "Suggestion icon column(s) discarded, must be 0 or 2 columns."); - } + protected void replaceText(CharSequence text) { } /** - * Overriding this allows us to write the selected query back into the box. - * NOTE: This is a vastly simplified version of SearchDialog.jamQuery() and does - * not universally support the search API. But it is sufficient for Google Search. + * We override this method so that we can allow a threshold of zero, which ACTV does not. */ @Override - public CharSequence convertToString(Cursor cursor) { - CharSequence result = null; - if (cursor != null) { - int column = cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY); - if (column >= 0) { - final String query = cursor.getString(column); - if (query != null) { - result = query; - } - } - } - return result; - } - - /** - * Get the query cursor for the search suggestions. - * - * TODO this is functionally identical to the version in SearchDialog.java. Perhaps it - * could be hoisted into SearchableInfo or some other shared spot. - * - * @param query The search text entered (so far) - * @return Returns a cursor with suggestions, or null if no suggestions - */ - private Cursor getSuggestions(final SearchableInfo searchable, final String query) { - Cursor cursor = null; - if (searchable.getSuggestAuthority() != null) { - try { - StringBuilder uriStr = new StringBuilder("content://"); - uriStr.append(searchable.getSuggestAuthority()); - - // if content path provided, insert it now - final String contentPath = searchable.getSuggestPath(); - if (contentPath != null) { - uriStr.append('/'); - uriStr.append(contentPath); - } - - // append standard suggestion query path - uriStr.append('/' + SearchManager.SUGGEST_URI_PATH_QUERY); - - // inject query, either as selection args or inline - String[] selArgs = null; - if (searchable.getSuggestSelection() != null) { // use selection if provided - selArgs = new String[] {query}; - } else { - uriStr.append('/'); // no sel, use REST pattern - uriStr.append(Uri.encode(query)); - } - - // finally, make the query - cursor = mContext.getContentResolver().query( - Uri.parse(uriStr.toString()), null, - searchable.getSuggestSelection(), selArgs, - null); - } catch (RuntimeException e) { - Log.w(TAG, "Search Suggestions query returned exception " + e.toString()); - cursor = null; - } - } - - return cursor; + public boolean enoughToFilter() { + return mThreshold <= 0 || super.enoughToFilter(); } /** - * Overriding this allows us to affect the way that an icon is loaded. Specifically, - * we can be more controlling about the resource path (and allow icons to come from other - * packages). - * - * TODO: This is 100% identical to the version in SearchDialog.java - * - * @param v ImageView to receive an image - * @param value the value retrieved from the cursor + * {@link AutoCompleteTextView#onKeyPreIme(int, KeyEvent)}) dismisses the drop-down on BACK, + * so we must override this method to modify the BACK behavior. */ @Override - public void setViewImage(ImageView v, String value) { - int resID; - Drawable img = null; - - try { - resID = Integer.parseInt(value); - if (resID != 0) { - img = mProviderResources.getDrawable(resID); + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { + if (mSearchDialog.backToPreviousComponent()) { + return true; } - } catch (NumberFormatException nfe) { - // img = null; - } catch (NotFoundException e2) { - // img = null; + return false; // will dismiss soft keyboard if necessary } - - // finally, set the image to whatever we've gotten - v.setImageDrawable(img); + return false; } - - /** - * This method is overridden purely to provide a bit of protection against - * flaky content providers. - * - * TODO: This is 100% identical to the version in SearchDialog.java - * - * @see android.widget.ListAdapter#getView(int, View, ViewGroup) - */ - @Override - public View getView(int position, View convertView, ViewGroup parent) { - try { - return super.getView(position, convertView, parent); - } catch (RuntimeException e) { - Log.w(TAG, "Search Suggestions cursor returned exception " + e.toString()); - // what can I return here? - View v = newView(mContext, mCursor, parent); - if (v != null) { - TextView tv = (TextView) v.findViewById(com.android.internal.R.id.text1); - tv.setText(e.toString()); - } - return v; + } + + protected boolean handleBackKey(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { + if (backToPreviousComponent()) { + return true; } + cancel(); + return true; } - + return false; } /** * Implements OnItemClickListener */ public void onItemClick(AdapterView parent, View view, int position, long id) { - // Log.d(LOG_TAG, "onItemClick() position " + position); - launchSuggestion(mSuggestionsAdapter, position); + if (DBG) Log.d(LOG_TAG, "onItemClick() position " + position); + launchSuggestion(position); } - + /** * Implements OnItemSelectedListener */ public void onItemSelected(AdapterView parent, View view, int position, long id) { - // Log.d(LOG_TAG, "onItemSelected() position " + position); - jamSuggestionQuery(true, parent, position); + if (DBG) Log.d(LOG_TAG, "onItemSelected() position " + position); + // A suggestion has been selected, rewrite the query if possible, + // otherwise the restore the original query. + if (REWRITE_QUERIES) { + rewriteQueryFromSuggestion(position); + } } /** * Implements OnItemSelectedListener */ public void onNothingSelected(AdapterView parent) { - // Log.d(LOG_TAG, "onNothingSelected()"); + if (DBG) Log.d(LOG_TAG, "onNothingSelected()"); + } + + /** + * Query rewriting. + */ + + private void rewriteQueryFromSuggestion(int position) { + Cursor c = mSuggestionsAdapter.getCursor(); + if (c == null) { + return; + } + if (c.moveToPosition(position)) { + // Get the new query from the suggestion. + CharSequence newQuery = mSuggestionsAdapter.convertToString(c); + if (newQuery != null) { + // The suggestion rewrites the query. + if (DBG) Log.d(LOG_TAG, "Rewriting query to '" + newQuery + "'"); + // Update the text field, without getting new suggestions. + setQuery(newQuery); + } else { + // The suggestion does not rewrite the query, restore the user's query. + if (DBG) Log.d(LOG_TAG, "Suggestion gives no rewrite, restoring user query."); + restoreUserQuery(); + } + } else { + // We got a bad position, restore the user's query. + Log.w(LOG_TAG, "Bad suggestion position: " + position); + restoreUserQuery(); + } + } + + /** + * Restores the query entered by the user if needed. + */ + private void restoreUserQuery() { + if (DBG) Log.d(LOG_TAG, "Restoring query to '" + mUserQuery + "'"); + setQuery(mUserQuery); + } + + /** + * Sets the text in the query box, without updating the suggestions. + */ + private void setQuery(CharSequence query) { + mSearchAutoComplete.setText(query, false); + if (query != null) { + mSearchAutoComplete.setSelection(query.length()); + } + } + + /** + * Sets the text in the query box, updating the suggestions. + */ + private void setUserQuery(String query) { + if (query == null) { + query = ""; + } + mUserQuery = query; + mSearchAutoComplete.setText(query); + mSearchAutoComplete.setSelection(query.length()); } /** diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index c1d66f4e7d7bcc7f0c269c35ae96a7b7b2b677a5..3bf37c3b2b0169e7bc5db227d0fd3a07fbd1772c 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -17,14 +17,21 @@ package android.app; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.res.Configuration; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.RemoteException; import android.os.ServiceManager; +import android.server.search.SearchableInfo; import android.view.KeyEvent; +import java.util.List; + /** * This class provides access to the system search services. * @@ -439,20 +446,18 @@ import android.view.KeyEvent; * * {@link #SUGGEST_COLUMN_ICON_1} * If your cursor includes this column, then all suggestions will be provided in an - * icons+text format. This value should be a reference (resource ID) of the icon to + * icons+text format. This value should be a reference to the icon to * draw on the left side, or it can be null or zero to indicate no icon in this row. - * You must provide both cursor columns, or neither. * - * No, but required if you also have {@link #SUGGEST_COLUMN_ICON_2} + * No. * * * {@link #SUGGEST_COLUMN_ICON_2} * If your cursor includes this column, then all suggestions will be provided in an - * icons+text format. This value should be a reference (resource ID) of the icon to + * icons+text format. This value should be a reference to the icon to * draw on the right side, or it can be null or zero to indicate no icon in this row. - * You must provide both cursor columns, or neither. * - * No, but required if you also have {@link #SUGGEST_COLUMN_ICON_1} + * No. * * * {@link #SUGGEST_COLUMN_INTENT_ACTION} @@ -807,7 +812,7 @@ import android.view.KeyEvent; * this way would be if you wish to partition it into separate sections with different search * behaviors; Otherwise this configuration is not recommended. * - *

Additional Metadata for search suggestions. If you have defined a content provider + *

Additional metadata for search suggestions. If you have defined a content provider * to generate search suggestions, you'll need to publish it to the system, and you'll need to * provide a bit of additional XML metadata in order to configure communications with it. * @@ -880,7 +885,7 @@ import android.view.KeyEvent; * * * - *

Additional Metadata for search action keys. For each action key that you would like to + *

Additional metadata for search action keys. For each action key that you would like to * define, you'll need to add an additional element defining that key, and using the attributes * discussed in Action Keys. A simple example is shown here: * @@ -956,6 +961,84 @@ import android.view.KeyEvent; * * * + *

Additional metadata for enabling voice search. To enable voice search for your + * activity, you can add fields to the metadata that enable and configure voice search. When + * enabled (and available on the device), a voice search button will be displayed in the + * Search UI. Clicking this button will launch a voice search activity. When the user has + * finished speaking, the voice search phrase will be transcribed into text and presented to the + * searchable activity as if it were a typed query. + * + *

Elements of search metadata that support voice search: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Attribute Description Required?
android:voiceSearchModeIf provided and non-zero, enables voice search. (Voice search may not be + * provided by the device, in which case these flags will have no effect.) The + * following mode bits are defined: + * + * + * + * + * + * + * + * + * + * + * + * + *
showVoiceSearchButtonIf set, display a voice search button. This only takes effect if voice + * search is available on the device. If set, then launchWebSearch or + * launchRecognizer must also be set.
launchWebSearchIf set, the voice search button will take the user directly to a + * built-in voice web search activity. Most applications will not use this + * flag, as it will take the user away from the activity in which search + * was invoked.
launchRecognizerIf set, the voice search button will take the user directly to a + * built-in voice recording activity. This activity will prompt the user + * to speak, transcribe the spoken text, and forward the resulting query + * text to the searchable activity, just as if the user had typed it into + * the search UI and clicked the search button.
No
android:voiceLanguageModelIf provided, this specifies the language model that should be used by the voice + * recognition system. + * See {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL} + * for more information. If not provided, the default value + * {@link android.speech.RecognizerIntent#LANGUAGE_MODEL_FREE_FORM} will be used.No
android:voicePromptTextIf provided, this specifies a prompt that will be displayed during voice input. + * (If not provided, a default prompt will be displayed.)No
android:voiceLanguageIf provided, this specifies the spoken language to be expected. This is only + * needed if it is different from the current value of + * {@link java.util.Locale#getDefault()}. + * No
android:voiceMaxResultsIf provided, enforces the maximum number of results to return, including the "best" + * result which will always be provided as the SEARCH intent's primary query. Must be + * one or greater. Use {@link android.speech.RecognizerIntent#EXTRA_RESULTS} + * to get the results from the intent. If not provided, the recognizer will choose + * how many results to return.No
+ * * *

Passing Search Context

* @@ -1076,6 +1159,13 @@ public class SearchManager */ public final static String ACTION_KEY = "action_key"; + /** + * Intent extra data key: This key will be used for the extra populated by the + * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column. + * {@hide} + */ + public final static String EXTRA_DATA_KEY = "intent_extra_data_key"; + /** * Intent extra data key: Use this key with Intent.ACTION_SEARCH and * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()} @@ -1092,14 +1182,34 @@ public class SearchManager * Typically you'll use this with a URI matcher. */ public final static String SUGGEST_URI_PATH_QUERY = "search_suggest_query"; - + /** * MIME type for suggestions data. You'll use this in your suggestions content provider * in the getType() function. */ - public final static String SUGGEST_MIME_TYPE = - "vnd.android.cursor.dir/vnd.android.search.suggest"; + public final static String SUGGEST_MIME_TYPE = + "vnd.android.cursor.dir/vnd.android.search.suggest"; + /** + * Uri path for shortcut validation. This is the path that the search manager will use when + * querying your content provider to refresh a shortcutted suggestion result and to check if it + * is still valid. When asked, a source may return an up to date result, or no result. No + * result indicates the shortcut refers to a no longer valid sugggestion. + * + * @see #SUGGEST_COLUMN_SHORTCUT_ID + * + * @hide pending API council approval + */ + public final static String SUGGEST_URI_PATH_SHORTCUT = "search_suggest_shortcut"; + + /** + * MIME type for shortcut validation. You'll use this in your suggestions content provider + * in the getType() function. + * + * @hide pending API council approval + */ + public final static String SHORTCUT_MIME_TYPE = + "vnd.android.cursor.item/vnd.android.search.suggest"; /** * Column name for suggestions cursor. Unused - can be null or column can be omitted. */ @@ -1117,20 +1227,58 @@ public class SearchManager public final static String SUGGEST_COLUMN_TEXT_2 = "suggest_text_2"; /** * Column name for suggestions cursor. Optional. If your cursor includes this column, - * then all suggestions will be provided in format that includes space for two small icons, + * then all suggestions will be provided in a format that includes space for two small icons, * one at the left and one at the right of each suggestion. The data in the column must - * be a a resource ID for the icon you wish to have displayed. If you include this column, - * you must also include {@link #SUGGEST_COLUMN_ICON_2}. + * be a resource ID of a drawable, or a URI in one of the following formats: + * + *
    + *
  • content ({@link android.content.ContentResolver#SCHEME_CONTENT})
  • + *
  • android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
  • + *
  • file ({@link android.content.ContentResolver#SCHEME_FILE})
  • + *
+ * + * See {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)} + * for more information on these schemes. */ public final static String SUGGEST_COLUMN_ICON_1 = "suggest_icon_1"; /** * Column name for suggestions cursor. Optional. If your cursor includes this column, - * then all suggestions will be provided in format that includes space for two small icons, + * then all suggestions will be provided in a format that includes space for two small icons, * one at the left and one at the right of each suggestion. The data in the column must - * be a a resource ID for the icon you wish to have displayed. If you include this column, - * you must also include {@link #SUGGEST_COLUMN_ICON_1}. + * be a resource ID of a drawable, or a URI in one of the following formats: + * + *
    + *
  • content ({@link android.content.ContentResolver#SCHEME_CONTENT})
  • + *
  • android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
  • + *
  • file ({@link android.content.ContentResolver#SCHEME_FILE})
  • + *
+ * + * See {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)} + * for more information on these schemes. */ public final static String SUGGEST_COLUMN_ICON_2 = "suggest_icon_2"; + /** + * Column name for suggestions cursor. Optional. If your cursor includes this column, + * then all suggestions will be provided in a format that includes space for two small icons, + * one at the left and one at the right of each suggestion. The data in the column must + * be a blob that contains a bitmap. + * + * This column overrides any icon provided in the {@link #SUGGEST_COLUMN_ICON_1} column. + * + * @hide + */ + public final static String SUGGEST_COLUMN_ICON_1_BITMAP = "suggest_icon_1_bitmap"; + /** + * Column name for suggestions cursor. Optional. If your cursor includes this column, + * then all suggestions will be provided in a format that includes space for two small icons, + * one at the left and one at the right of each suggestion. The data in the column must + * be a blob that contains a bitmap. + * + * This column overrides any icon provided in the {@link #SUGGEST_COLUMN_ICON_2} column. + * + * @hide + */ + public final static String SUGGEST_COLUMN_ICON_2_BITMAP = "suggest_icon_2_bitmap"; /** * Column name for suggestions cursor. Optional. If this column exists and * this element exists at the given row, this is the action that will be used when @@ -1151,6 +1299,14 @@ public class SearchManager * it is more efficient to specify it using XML metadata and omit it from the cursor. */ public final static String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data"; + /** + * Column name for suggestions cursor. Optional. This column allows suggestions + * to provide additional arbitrary data which will be included as an extra under the key + * {@link #EXTRA_DATA_KEY}. + * + * @hide pending API council approval + */ + public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data"; /** * Column name for suggestions cursor. Optional. If this column exists and * this element exists at the given row, then "/" and this value will be appended to the data @@ -1166,6 +1322,83 @@ public class SearchManager */ public final static String SUGGEST_COLUMN_QUERY = "suggest_intent_query"; + /** + * Column name for suggestions cursor. Optional. This column is used to indicate whether + * a search suggestion should be stored as a shortcut, and whether it should be validated. If + * missing, the result will be stored as a shortcut and never validated. If set to + * {@link #SUGGEST_NEVER_MAKE_SHORTCUT}, the result will not be stored as a shortcut. + * Otherwise, the shortcut id will be used to check back for validation via + * {@link #SUGGEST_URI_PATH_SHORTCUT}. + * + * @hide Pending API council approval. + */ + public final static String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id"; + + /** + * Column value for suggestion column {@link #SUGGEST_COLUMN_SHORTCUT_ID} when a suggestion + * should not be stored as a shortcut in global search. + * + * @hide Pending API council approval. + */ + public final static String SUGGEST_NEVER_MAKE_SHORTCUT = "_-1"; + + /** + * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION}, + * the search dialog will switch to a different suggestion source when the + * suggestion is clicked. + * + * {@link #SUGGEST_COLUMN_INTENT_DATA} must contain + * the flattened {@link ComponentName} of the activity which is to be searched. + * + * TODO: Should {@link #SUGGEST_COLUMN_INTENT_DATA} instead contain a URI in the format + * used by {@link android.provider.Applications}? + * + * TODO: This intent should be protected by the same permission that we use + * for replacing the global search provider. + * + * The query text field will be set to the value of {@link #SUGGEST_COLUMN_QUERY}. + * + * @hide Pending API council approval. + */ + public final static String INTENT_ACTION_CHANGE_SEARCH_SOURCE + = "android.search.action.CHANGE_SEARCH_SOURCE"; + + /** + * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION}, + * the search dialog will call {@link Cursor#respond(Bundle)} when the + * suggestion is clicked. + * + * The {@link Bundle} argument will be constructed + * in the same way as the "extra" bundle included in an Intent constructed + * from the suggestion. + * + * @hide Pending API council approval. + */ + public final static String INTENT_ACTION_CURSOR_RESPOND + = "android.search.action.CURSOR_RESPOND"; + + /** + * Intent action for finding the global search activity. + * The global search provider should handle this intent. + * + * @hide Pending API council approval. + */ + public final static String INTENT_ACTION_GLOBAL_SEARCH + = "android.search.action.GLOBAL_SEARCH"; + + /** + * Intent action for starting the global search settings activity. + * The global search provider should handle this intent. + * + * @hide Pending API council approval. + */ + public final static String INTENT_ACTION_SEARCH_SETTINGS + = "android.search.action.SEARCH_SETTINGS"; + + /** + * Reference to the shared system search service. + */ + private static ISearchManager sService = getSearchManagerService(); private final Context mContext; private final Handler mHandler; @@ -1179,12 +1412,6 @@ public class SearchManager mContext = context; mHandler = handler; } - private static ISearchManager mService; - - static { - mService = ISearchManager.Stub.asInterface( - ServiceManager.getService(Context.SEARCH_SERVICE)); - } /** * Launch search UI. @@ -1381,5 +1608,109 @@ public class SearchManager mSearchDialog.onConfigurationChanged(newConfig); } } - + + private static ISearchManager getSearchManagerService() { + return ISearchManager.Stub.asInterface( + ServiceManager.getService(Context.SEARCH_SERVICE)); + } + + /** + * Gets information about a searchable activity. This method is static so that it can + * be used from non-Activity contexts. + * + * @param componentName The activity to get searchable information for. + * @param globalSearch If false, return information about the given activity. + * If true, return information about the global search activity. + * @return Searchable information, or null if the activity is not searchable. + * + * @hide because SearchableInfo is not part of the API. + */ + public static SearchableInfo getSearchableInfo(ComponentName componentName, + boolean globalSearch) { + try { + return sService.getSearchableInfo(componentName, globalSearch); + } catch (RemoteException e) { + return null; + } + } + + /** + * Checks whether the given searchable is the default searchable. + * + * @hide because SearchableInfo is not part of the API. + */ + public static boolean isDefaultSearchable(SearchableInfo searchable) { + SearchableInfo defaultSearchable = SearchManager.getSearchableInfo(null, true); + return defaultSearchable != null + && defaultSearchable.getSearchActivity().equals(searchable.getSearchActivity()); + } + + /** + * Gets a cursor with search suggestions. This method is static so that it can + * be used from non-Activity context. + * + * @param searchable Information about how to get the suggestions. + * @param query The search text entered (so far). + * @return a cursor with suggestions, or null the suggestion query failed. + * + * @hide because SearchableInfo is not part of the API. + */ + public static Cursor getSuggestions(Context context, SearchableInfo searchable, String query) { + if (searchable == null) { + return null; + } + + String authority = searchable.getSuggestAuthority(); + if (authority == null) { + return null; + } + + Uri.Builder uriBuilder = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(authority); + + // if content path provided, insert it now + final String contentPath = searchable.getSuggestPath(); + if (contentPath != null) { + uriBuilder.appendEncodedPath(contentPath); + } + + // append standard suggestion query path + uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY); + + // get the query selection, may be null + String selection = searchable.getSuggestSelection(); + // inject query, either as selection args or inline + String[] selArgs = null; + if (selection != null) { // use selection if provided + selArgs = new String[] { query }; + } else { // no selection, use REST pattern + uriBuilder.appendPath(query); + } + + Uri uri = uriBuilder + .query("") // TODO: Remove, workaround for a bug in Uri.writeToParcel() + .fragment("") // TODO: Remove, workaround for a bug in Uri.writeToParcel() + .build(); + + // finally, make the query + return context.getContentResolver().query(uri, null, selection, selArgs, null); + } + + /** + * Returns a list of the searchable activities that can be included in global search. + * + * @return a list containing searchable information for all searchable activities + * that have the exported attribute set in their searchable + * meta-data. + * + * @hide because SearchableInfo is not part of the API. + */ + public static List getSearchablesInGlobalSearch() { + try { + return sService.getSearchablesInGlobalSearch(); + } catch (RemoteException e) { + return null; + } + } } diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..6a02fc930a1c3bdf1a45e3fe72398459dbd4dbc1 --- /dev/null +++ b/core/java/android/app/SuggestionsAdapter.java @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources.NotFoundException; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.server.search.SearchableInfo; +import android.text.Html; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.ImageView; +import android.widget.ResourceCursorAdapter; +import android.widget.TextView; + +import java.io.FileNotFoundException; +import java.util.WeakHashMap; + +/** + * Provides the contents for the suggestion drop-down list.in {@link SearchDialog}. + * + * @hide + */ +class SuggestionsAdapter extends ResourceCursorAdapter { + private static final boolean DBG = false; + private static final String LOG_TAG = "SuggestionsAdapter"; + + private SearchableInfo mSearchable; + private Context mProviderContext; + private WeakHashMap mOutsideDrawablesCache; + + // Cached column indexes, updated when the cursor changes. + private int mFormatCol; + private int mText1Col; + private int mText2Col; + private int mIconName1Col; + private int mIconName2Col; + private int mIconBitmap1Col; + private int mIconBitmap2Col; + + public SuggestionsAdapter(Context context, SearchableInfo searchable, + WeakHashMap outsideDrawablesCache) { + super(context, + com.android.internal.R.layout.search_dropdown_item_icons_2line, + null, // no initial cursor + true); // auto-requery + mSearchable = searchable; + + // set up provider resources (gives us icons, etc.) + Context activityContext = mSearchable.getActivityContext(mContext); + mProviderContext = mSearchable.getProviderContext(mContext, activityContext); + + mOutsideDrawablesCache = outsideDrawablesCache; + } + + /** + * Overridden to always return false, since we cannot be sure that + * suggestion sources return stable IDs. + */ + @Override + public boolean hasStableIds() { + return false; + } + + /** + * Use the search suggestions provider to obtain a live cursor. This will be called + * in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions). + * The results will be processed in the UI thread and changeCursor() will be called. + */ + @Override + public Cursor runQueryOnBackgroundThread(CharSequence constraint) { + if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")"); + String query = (constraint == null) ? "" : constraint.toString(); + try { + return SearchManager.getSuggestions(mContext, mSearchable, query); + } catch (RuntimeException e) { + Log.w(LOG_TAG, "Search suggestions query threw an exception.", e); + return null; + } + } + + /** + * Cache columns. + */ + @Override + public void changeCursor(Cursor c) { + if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")"); + super.changeCursor(c); + if (c != null) { + mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT); + mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); + mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); + mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); + mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); + mIconBitmap1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1_BITMAP); + mIconBitmap2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2_BITMAP); + } + } + + /** + * Tags the view with cached child view look-ups. + */ + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View v = super.newView(context, cursor, parent); + v.setTag(new ChildViewCache(v)); + return v; + } + + /** + * Cache of the child views of drop-drown list items, to avoid looking up the children + * each time the contents of a list item are changed. + */ + private final static class ChildViewCache { + public final TextView mText1; + public final TextView mText2; + public final ImageView mIcon1; + public final ImageView mIcon2; + + public ChildViewCache(View v) { + mText1 = (TextView) v.findViewById(com.android.internal.R.id.text1); + mText2 = (TextView) v.findViewById(com.android.internal.R.id.text2); + mIcon1 = (ImageView) v.findViewById(com.android.internal.R.id.icon1); + mIcon2 = (ImageView) v.findViewById(com.android.internal.R.id.icon2); + } + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + ChildViewCache views = (ChildViewCache) view.getTag(); + boolean isHtml = false; + if (mFormatCol >= 0) { + String format = cursor.getString(mFormatCol); + isHtml = "html".equals(format); + } + setViewText(cursor, views.mText1, mText1Col, isHtml); + setViewText(cursor, views.mText2, mText2Col, isHtml); + setViewIcon(cursor, views.mIcon1, mIconBitmap1Col, mIconName1Col); + setViewIcon(cursor, views.mIcon2, mIconBitmap2Col, mIconName2Col); + } + + private void setViewText(Cursor cursor, TextView v, int textCol, boolean isHtml) { + if (v == null) { + return; + } + CharSequence text = null; + if (textCol >= 0) { + String str = cursor.getString(textCol); + text = (str != null && isHtml) ? Html.fromHtml(str) : str; + } + // Set the text even if it's null, since we need to clear any previous text. + v.setText(text); + + if (TextUtils.isEmpty(text)) { + v.setVisibility(View.GONE); + } else { + v.setVisibility(View.VISIBLE); + } + } + + private void setViewIcon(Cursor cursor, ImageView v, int iconBitmapCol, int iconNameCol) { + if (v == null) { + return; + } + Drawable drawable = null; + // First try the bitmap column + if (iconBitmapCol >= 0) { + byte[] data = cursor.getBlob(iconBitmapCol); + if (data != null) { + Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); + if (bitmap != null) { + drawable = new BitmapDrawable(bitmap); + } + } + } + // If there was no bitmap, try the icon resource column. + if (drawable == null && iconNameCol >= 0) { + String value = cursor.getString(iconNameCol); + drawable = getDrawableFromResourceValue(value); + } + // Set the icon even if the drawable is null, since we need to clear any + // previous icon. + v.setImageDrawable(drawable); + + if (drawable == null) { + v.setVisibility(View.GONE); + } else { + v.setVisibility(View.VISIBLE); + } + } + + /** + * Gets the text to show in the query field when a suggestion is selected. + * + * @param cursor The Cursor to read the suggestion data from. The Cursor should already + * be moved to the suggestion that is to be read from. + * @return The text to show, or null if the query should not be + * changed when selecting this suggestion. + */ + @Override + public CharSequence convertToString(Cursor cursor) { + if (cursor == null) { + return null; + } + + String query = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_QUERY); + if (query != null) { + return query; + } + + if (mSearchable.shouldRewriteQueryFromData()) { + String data = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_INTENT_DATA); + if (data != null) { + return data; + } + } + + if (mSearchable.shouldRewriteQueryFromText()) { + String text1 = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_TEXT_1); + if (text1 != null) { + return text1; + } + } + + return null; + } + + /** + * This method is overridden purely to provide a bit of protection against + * flaky content providers. + * + * @see android.widget.ListAdapter#getView(int, View, ViewGroup) + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + try { + return super.getView(position, convertView, parent); + } catch (RuntimeException e) { + Log.w(LOG_TAG, "Search suggestions cursor threw exception.", e); + // Put exception string in item title + View v = newView(mContext, mCursor, parent); + if (v != null) { + ChildViewCache views = (ChildViewCache) v.getTag(); + TextView tv = views.mText1; + tv.setText(e.toString()); + } + return v; + } + } + + /** + * Gets a drawable given a value provided by a suggestion provider. + * + * This value could be just the string value of a resource id + * (e.g., "2130837524"), in which case we will try to retrieve a drawable from + * the provider's resources. If the value is not an integer, it is + * treated as a Uri and opened with + * {@link ContentResolver#openOutputStream(android.net.Uri, String)}. + * + * All resources and URIs are read using the suggestion provider's context. + * + * If the string is not formatted as expected, or no drawable can be found for + * the provided value, this method returns null. + * + * @param drawableId a string like "2130837524", + * "android.resource://com.android.alarmclock/2130837524", + * or "content://contacts/photos/253". + * @return a Drawable, or null if none found + */ + private Drawable getDrawableFromResourceValue(String drawableId) { + if (drawableId == null || drawableId.length() == 0 || "0".equals(drawableId)) { + return null; + } + + // First, check the cache. + Drawable drawable = mOutsideDrawablesCache.get(drawableId); + if (drawable != null) return drawable; + + try { + // Not cached, try using it as a plain resource ID in the provider's context. + int resourceId = Integer.parseInt(drawableId); + drawable = mProviderContext.getResources().getDrawable(resourceId); + } catch (NumberFormatException nfe) { + // The id was not an integer resource id. + // Let the ContentResolver handle content, android.resource and file URIs. + try { + Uri uri = Uri.parse(drawableId); + drawable = Drawable.createFromStream( + mProviderContext.getContentResolver().openInputStream(uri), + null); + } catch (FileNotFoundException fnfe) { + // drawable = null; + } + + // If we got a drawable for this resource id, then stick it in the + // map so we don't do this lookup again. + if (drawable != null) { + mOutsideDrawablesCache.put(drawableId, drawable); + } + } catch (NotFoundException nfe) { + // Resource could not be found + // drawable = null; + } + + return drawable; + } + + /** + * Gets the value of a string column by name. + * + * @param cursor Cursor to read the value from. + * @param columnName The name of the column to read. + * @return The value of the given column, or null + * if the cursor does not contain the given column. + */ + public static String getColumnString(Cursor cursor, String columnName) { + int col = cursor.getColumnIndex(columnName); + if (col == -1) { + return null; + } + return cursor.getString(col); + } + +} diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java index f70de9cde67e09bdf339327008168381ecd8296f..26712a10f0ce45fe4c34dc75c04b85a7ab696f5c 100755 --- a/core/java/android/appwidget/AppWidgetProvider.java +++ b/core/java/android/appwidget/AppWidgetProvider.java @@ -22,7 +22,7 @@ import android.content.Intent; import android.os.Bundle; /** - * A conveience class to aid in implementing an AppWidget provider. + * A convenience class to aid in implementing an AppWidget provider. * Everything you can do with AppWidgetProvider, you can do with a regular {@link BroadcastReceiver}. * AppWidgetProvider merely parses the relevant fields out of the Intent that is received in * {@link #onReceive(Context,Intent) onReceive(Context,Intent)}, and calls hook methods @@ -30,11 +30,9 @@ import android.os.Bundle; * *

Extend this class and override one or more of the {@link #onUpdate}, {@link #onDeleted}, * {@link #onEnabled} or {@link #onDisabled} methods to implement your own AppWidget functionality. - * - *

Sample Code

- * For an example of how to write a AppWidget provider, see the - * android.appwidget - * package overview. + *

+ *

For an example of how to write a AppWidget provider, see the + * AppWidgets documentation.

*/ public class AppWidgetProvider extends BroadcastReceiver { /** diff --git a/core/java/android/appwidget/package.html b/core/java/android/appwidget/package.html index b6cd9c74d02ef04c51cc744b943344b9bab09b59..2b85bd5a41a4e9abed7da506fb563e5672a6dae6 100644 --- a/core/java/android/appwidget/package.html +++ b/core/java/android/appwidget/package.html @@ -3,127 +3,22 @@ views are called widgets, and are published by "AppWidget providers." The component that can contain widgets is called a "AppWidget host."

-

AppWidget Providers

- -

AppWidget Hosts

+

For more information, see the +AppWidgets +documentation in the Dev Guide.

{@more}

AppWidget Providers

-

-Any application can publish widgets. All an application needs to do to publish a widget is +

Any application can publish widgets. All an application needs to do to publish a widget is to have a {@link android.content.BroadcastReceiver} that receives the {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} intent, and provide some meta-data about the widget. Android provides the {@link android.appwidget.AppWidgetProvider} class, which extends BroadcastReceiver, as a convenience class to aid in handling the broadcasts. -

Declaring a widget in the AndroidManifest

- -

-First, declare the {@link android.content.BroadcastReceiver} in your application's -AndroidManifest.xml file. - -{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml AppWidgetProvider} - -

-The <receiver> element has the following attributes: -

    -
  • android:name - which specifies the - {@link android.content.BroadcastReceiver} or {@link android.appwidget.AppWidgetProvider} - class.
  • -
  • android:label - which specifies the string resource that - will be shown by the widget picker as the label.
  • -
  • android:icon - which specifies the drawable resource that - will be shown by the widget picker as the icon.
  • -
- -

-The <intent-filter> element tells the {@link android.content.pm.PackageManager} -that this {@link android.content.BroadcastReceiver} receives the {@link -android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast. -The widget manager will send other broadcasts directly to your widget provider as required. -It is only necessary to explicitly declare that you accept the {@link -android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast. - -

-The <meta-data> element tells the widget manager which xml resource to -read to find the {@link android.appwidget.AppWidgetProviderInfo} for your widget provider. It has the following -attributes: -

    -
  • android:name="android.appwidget.provider" - identifies this meta-data - as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.
  • -
  • android:resource - is the xml resource to use as that descriptor.
  • -
- - -

Adding the {@link android.appwidget.AppWidgetProviderInfo AppWidgetProviderInfo} meta-data

- -

-For a widget, the values in the {@link android.appwidget.AppWidgetProviderInfo} structure are supplied -in an XML resource. In the example above, the xml resource is referenced with -android:resource="@xml/appwidget_info". That XML file would go in your application's -directory at res/xml/appwidget_info.xml. Here is a simple example. - -{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml AppWidgetProviderInfo} - -

-The attributes are as documented in the {@link android.appwidget.AppWidgetProviderInfo GagetInfo} class. (86400000 milliseconds means once per day) - - -

Using the {@link android.appwidget.AppWidgetProvider AppWidgetProvider} class

- -

The AppWidgetProvider class is the easiest way to handle the widget provider intent broadcasts. -See the src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java -sample class in ApiDemos for an example. - -

Keep in mind that since the the AppWidgetProvider is a BroadcastReceiver, -your process is not guaranteed to keep running after the callback methods return. See -Application Fundamentals > -Broadcast Receiver Lifecycle for more information. - - - -

AppWidget Configuration UI

- -

-Widget hosts have the ability to start a configuration activity when a widget is instantiated. -The activity should be declared as normal in AndroidManifest.xml, and it should be listed in -the AppWidgetProviderInfo XML file in the android:configure attribute. - -

The activity you specified will be launched with the {@link -android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE} action. See the documentation for that -action for more info. - -

See the src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java -sample class in ApiDemos for an example. - - - -

AppWidget Broadcast Intents

- -

{@link android.appwidget.AppWidgetProvider} is just a convenience class. If you would like -to receive the widget broadcasts directly, you can. The four intents you need to care about are: -

    -
  • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}
  • -
  • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}
  • -
  • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}
  • -
  • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}
  • -
- -

By way of example, the implementation of -{@link android.appwidget.AppWidgetProvider#onReceive} is quite simple:

- -{@sample frameworks/base/core/java/android/appwidget/AppWidgetProvider.java onReceive} -

AppWidget Hosts

Widget hosts are the containers in which widgets can be placed. Most of the look and feel @@ -132,5 +27,6 @@ widgets, but the lock screen could also contain widgets, and it would have a dif adding, removing and otherwise managing widgets.

For more information on implementing your own widget host, see the {@link android.appwidget.AppWidgetHost AppWidgetHost} class.

+ diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java new file mode 100644 index 0000000000000000000000000000000000000000..555494e595240b6ba99379b94492d48d82bd40a1 --- /dev/null +++ b/core/java/android/backup/BackupDataOutput.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +import android.content.Context; + +import java.io.FileDescriptor; + +/** @hide */ +public class BackupDataOutput { + /* package */ FileDescriptor fd; + + public static final int OP_UPDATE = 1; + public static final int OP_DELETE = 2; + + public BackupDataOutput(Context context, FileDescriptor fd) { + this.fd = fd; + } + + public void close() { + // do we close the fd? + } + public native void flush(); + public native void write(byte[] buffer); + public native void write(int oneByte); + public native void write(byte[] buffer, int offset, int count); + + public native void writeOperation(int op); + public native void writeKey(String key); +} + diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java new file mode 100644 index 0000000000000000000000000000000000000000..6f0b2eef603f7f720072dedaadbd02734fcd4973 --- /dev/null +++ b/core/java/android/backup/BackupManager.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; + +/** + * BackupManager is the interface to the system's backup service. + * Applications simply instantiate one, and then use that instance + * to communicate with the backup infrastructure. + * + *

When your application has made changes to data it wishes to have + * backed up, call {@link #dataChanged()} to notify the backup service. + * The system will then schedule a backup operation to occur in the near + * future. Repeated calls to {@link #dataChanged()} have no further effect + * until the backup operation actually occurs. + * + *

The backup operation itself begins with the system launching the + * {@link BackupService} subclass declared in your manifest. See the documentation + * for {@link BackupService} for a detailed description of how the backup then proceeds. + * + * @hide pending API solidification + */ +public class BackupManager { + private Context mContext; + private IBackupManager mService; + + /** + * Constructs a BackupManager object through which the application can + * communicate with the Android backup system. + * + * @param context The {@link android.content.Context} that was provided when + * one of your application's {@link android.app.Activity Activities} + * was created. + */ + public BackupManager(Context context) { + mContext = context; + mService = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + } + + /** + * Notifies the Android backup system that your application wishes to back up + * new changes to its data. A backup operation using your application's + * {@link BackupService} subclass will be scheduled when you call this method. + */ + public void dataChanged() { + try { + mService.dataChanged(mContext.getPackageName()); + } catch (RemoteException e) { + } + } +} diff --git a/core/java/android/backup/BackupService.java b/core/java/android/backup/BackupService.java new file mode 100644 index 0000000000000000000000000000000000000000..50a5921c0421e4449a12cd8468ecfd5e5765a5de --- /dev/null +++ b/core/java/android/backup/BackupService.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Service; +import android.backup.IBackupService; +import android.content.Intent; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Log; + +/** + * This is the central interface between an application and Android's + * settings backup mechanism. + * + * In order to use the backup service, your application must implement a + * subclass of BackupService, and declare an intent filter + * in the application manifest specifying that your BackupService subclass + * handles the {@link BackupService#SERVICE_ACTION} intent action. For example: + * + *

+ *      <!-- Use the class "MyBackupService" to perform backups for my app -->
+ *      <service android:name=".MyBackupService">
+ *          <intent-filter>
+ *              <action android:name="android.backup.BackupService.SERVICE" />
+ *          </intent-filter>
+ *      </service>
+ * + * @hide pending API solidification + */ + +public abstract class BackupService extends Service { + /** + * Service Action: Participate in the backup infrastructure. Applications + * that wish to use the Android backup mechanism must provide an exported + * subclass of BackupService and give it an {@link android.content.IntentFilter + * IntentFilter} that accepts this action. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_ACTION = "android.backup.BackupService.SERVICE"; + + /** + * The application is being asked to write any data changed since the + * last time it performed a backup operation. The state data recorded + * during the last backup pass is provided in the oldState file descriptor. + * If oldState is null, no old state is available and the application should perform + * a full backup. In both cases, a representation of the final backup state after + * this pass should be written to the file pointed to by the newStateFd file descriptor. + * + * @param oldState An open, read-only ParcelFileDescriptor pointing to the last backup + * state provided by the application. May be null, in which + * case no prior state is being provided and the application should + * perform a full backup. + * @param data An open, read/write ParcelFileDescriptor pointing to the backup data + * destination. Typically the application will use backup helper + * classes to write to this file. + * @param newState An open, read/write ParcelFileDescriptor pointing to an empty + * file. The application should record the final backup state + * here after writing the requested data to dataFd. + */ + public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState); + + /** + * The application is being restored from backup, and should replace any + * existing data with the contents of the backup. The backup data is + * provided in the file pointed to by the dataFd file descriptor. Once + * the restore is finished, the application should write a representation + * of the final state to the newStateFd file descriptor, + * + * @param data An open, read-only ParcelFileDescriptor pointing to a full snapshot + * of the application's data. + * @param newState An open, read/write ParcelFileDescriptor pointing to an empty + * file. The application should record the final backup state + * here after restoring its data from dataFd. + */ + public abstract void onRestore(ParcelFileDescriptor /* TODO: BackupDataInput */ data, ParcelFileDescriptor newState); + + + // ----- Core implementation ----- + + /** + * Returns the private interface called by the backup system. Applications will + * not typically override this. + */ + public IBinder onBind(Intent intent) { + if (intent.getAction().equals(SERVICE_ACTION)) { + return mBinder; + } + return null; + } + + private final IBinder mBinder = new BackupServiceBinder().asBinder(); + + // ----- IBackupService binder interface ----- + private class BackupServiceBinder extends IBackupService.Stub { + public void doBackup(ParcelFileDescriptor oldState, + ParcelFileDescriptor data, + ParcelFileDescriptor newState) throws RemoteException { + // !!! TODO - real implementation; for now just invoke the callbacks directly + Log.v("BackupServiceBinder", "doBackup() invoked"); + BackupDataOutput output = new BackupDataOutput(BackupService.this, + data.getFileDescriptor()); + try { + BackupService.this.onBackup(oldState, output, newState); + } catch (RuntimeException ex) { + Log.d("BackupService", "onBackup (" + + BackupService.this.getClass().getName() + ") threw", ex); + throw ex; + } + } + + public void doRestore(ParcelFileDescriptor data, + ParcelFileDescriptor newState) throws RemoteException { + // !!! TODO - real implementation; for now just invoke the callbacks directly + Log.v("BackupServiceBinder", "doRestore() invoked"); + BackupService.this.onRestore(data, newState); + } + } +} diff --git a/core/java/android/backup/FileBackupHelper.java b/core/java/android/backup/FileBackupHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..05159dc3bdf21bb34a7029cea18aa01deff98317 --- /dev/null +++ b/core/java/android/backup/FileBackupHelper.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +import android.content.Context; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.FileDescriptor; + +/** @hide */ +public class FileBackupHelper { + private static final String TAG = "FileBackupHelper"; + + /** + * Based on oldState, determine which of the files from the application's data directory + * need to be backed up, write them to the data stream, and fill in newState with the + * state as it exists now. + */ + public static void performBackup(Context context, + ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState, String[] files) { + String basePath = context.getFilesDir().getAbsolutePath(); + performBackup_checked(basePath, oldState, data, newState, files); + } + + /** + * Check the parameters so the native code doens't have to throw all the exceptions + * since it's easier to do that from java. + */ + static void performBackup_checked(String basePath, + ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState, String[] files) { + if (files.length == 0) { + return; + } + if (basePath == null) { + throw new NullPointerException(); + } + // oldStateFd can be null + FileDescriptor oldStateFd = oldState != null ? oldState.getFileDescriptor() : null; + if (data.fd == null) { + throw new NullPointerException(); + } + FileDescriptor newStateFd = newState.getFileDescriptor(); + if (newStateFd == null) { + throw new NullPointerException(); + } + + int err = performBackup_native(basePath, oldStateFd, data.fd, newStateFd, files); + + if (err != 0) { + throw new RuntimeException("Backup failed"); // TODO: more here + } + } + + native private static int performBackup_native(String basePath, FileDescriptor oldState, + FileDescriptor data, FileDescriptor newState, String[] files); +} diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl new file mode 100644 index 0000000000000000000000000000000000000000..cf22798507a8a7245fc5fe9f65787c037abdbb26 --- /dev/null +++ b/core/java/android/backup/IBackupManager.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +/** + * Direct interface to the Backup Manager Service that applications invoke on. The only + * operation currently needed is a simple notification that the app has made changes to + * data it wishes to back up, so the system should run a backup pass. + * + * Apps will use the {@link android.backup.BackupManager} class rather than going through + * this Binder interface directly. + * + * {@hide} + */ +interface IBackupManager { + /** + * Tell the system service that the caller has made changes to its + * data, and therefore needs to undergo an incremental backup pass. + */ + oneway void dataChanged(String packageName); + + /** + * Schedule a full backup of the given package. + * !!! TODO: protect with a signature-or-system permission? + */ + oneway void scheduleFullBackup(String packageName); +} diff --git a/core/java/android/backup/IBackupService.aidl b/core/java/android/backup/IBackupService.aidl new file mode 100644 index 0000000000000000000000000000000000000000..1bde8eac9bdb175c884ecd323cff23de6b1c1b82 --- /dev/null +++ b/core/java/android/backup/IBackupService.aidl @@ -0,0 +1,59 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +import android.os.ParcelFileDescriptor; + +/** + * Interface presented by applications being asked to participate in the + * backup & restore mechanism. End user code does not typically implement + * this interface; they subclass BackupService instead. + * + * {@hide} + */ +interface IBackupService { + /** + * Request that the app perform an incremental backup. + * + * @param oldState Read-only file containing the description blob of the + * app's data state as of the last backup operation's completion. + * This file is empty or invalid when a full backup is being + * requested. + * + * @param data Read-write file, empty when onBackup() is called, that + * is the data destination for this backup pass's incrementals. + * + * @param newState Read-write file, empty when onBackup() is called, + * where the new state blob is to be recorded. + */ + void doBackup(in ParcelFileDescriptor oldState, + in ParcelFileDescriptor data, + in ParcelFileDescriptor newState); + + /** + * Restore an entire data snapshot to the application. + * + * @param data Read-only file containing the full data snapshot of the + * app's backup. This is to be a replacement of the app's + * current data, not to be merged into it. + * + * @param newState Read-write file, empty when onRestore() is called, + * that is to be written with the state description that holds after + * the restore has been completed. + */ + void doRestore(in ParcelFileDescriptor data, in ParcelFileDescriptor newState); +} diff --git a/core/java/android/backup/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..8627f08cf57b16884ace6386e9d93e73895ac22e --- /dev/null +++ b/core/java/android/backup/SharedPreferencesBackupHelper.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.backup; + +import android.content.Context; +import android.os.ParcelFileDescriptor; + +import java.io.FileDescriptor; + +/** @hide */ +public class SharedPreferencesBackupHelper { + public static void performBackup(Context context, + ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot, + BackupDataOutput data, String[] prefGroups) { + String basePath = "/xxx"; //context.getPreferencesDir(); + + // make filenames for the prefGroups + final int N = prefGroups.length; + String[] files = new String[N]; + for (int i=0; i CREATOR = new Creator() { + public ActiveSyncInfo createFromParcel(Parcel in) { + return new ActiveSyncInfo(in); + } + + public ActiveSyncInfo[] newArray(int size) { + return new ActiveSyncInfo[size]; + } + }; +} \ No newline at end of file diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java index 32c68647709adc0de75c025195a4e08d502e15de..045520216ca299002f5b8fc493eb8498e88ff191 100644 --- a/core/java/android/content/ComponentName.java +++ b/core/java/android/content/ComponentName.java @@ -18,6 +18,7 @@ package android.content; import android.os.Parcel; import android.os.Parcelable; +import java.lang.Comparable; /** * Identifier for a specific application component @@ -29,7 +30,7 @@ import android.os.Parcelable; * name inside of that package. * */ -public final class ComponentName implements Parcelable { +public final class ComponentName implements Parcelable, Comparable { private final String mPackage; private final String mClass; @@ -196,6 +197,15 @@ public final class ComponentName implements Parcelable { public int hashCode() { return mPackage.hashCode() + mClass.hashCode(); } + + public int compareTo(ComponentName that) { + int v; + v = this.mPackage.compareTo(that.mPackage); + if (v != 0) { + return v; + } + return this.mClass.compareTo(that.mClass); + } public int describeContents() { return 0; diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 0d886ee23e8d1117296a8c38661ae4dcbfc5d255..74144fc5608fa5b3c219f887f539f8ff12a1efe6 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -25,9 +25,13 @@ import android.database.CursorWrapper; import android.database.IContentObserver; import android.net.Uri; import android.os.Bundle; +import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ServiceManager; import android.text.TextUtils; +import android.util.Config; +import android.util.Log; import java.io.File; import java.io.FileInputStream; @@ -85,8 +89,7 @@ public abstract class ContentResolver { */ public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir"; - public ContentResolver(Context context) - { + public ContentResolver(Context context) { mContext = context; } @@ -541,7 +544,7 @@ public abstract class ContentResolver { A null value will remove an existing field value. * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause (excluding the WHERE itself). - * @return the URL of the newly created row + * @return The number of rows updated. * @throws NullPointerException if uri or values are null */ public final int update(Uri uri, ContentValues values, String where, @@ -605,7 +608,7 @@ public abstract class ContentResolver { ContentObserver observer) { try { - ContentServiceNative.getDefault().registerContentObserver(uri, notifyForDescendents, + getContentService().registerContentObserver(uri, notifyForDescendents, observer.getContentObserver()); } catch (RemoteException e) { } @@ -621,7 +624,7 @@ public abstract class ContentResolver { try { IContentObserver contentObserver = observer.releaseContentObserver(); if (contentObserver != null) { - ContentServiceNative.getDefault().unregisterContentObserver( + getContentService().unregisterContentObserver( contentObserver); } } catch (RemoteException e) { @@ -651,7 +654,7 @@ public abstract class ContentResolver { */ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { try { - ContentServiceNative.getDefault().notifyChange( + getContentService().notifyChange( uri, observer == null ? null : observer.getContentObserver(), observer != null && observer.deliverSelfNotifications(), syncToNetwork); } catch (RemoteException e) { @@ -677,7 +680,7 @@ public abstract class ContentResolver { public void startSync(Uri uri, Bundle extras) { validateSyncExtrasBundle(extras); try { - ContentServiceNative.getDefault().startSync(uri, extras); + getContentService().startSync(uri, extras); } catch (RemoteException e) { } } @@ -718,7 +721,7 @@ public abstract class ContentResolver { public void cancelSync(Uri uri) { try { - ContentServiceNative.getDefault().cancelSync(uri); + getContentService().cancelSync(uri); } catch (RemoteException e) { } } @@ -779,6 +782,22 @@ public abstract class ContentResolver { } } + /** @hide */ + public static final String CONTENT_SERVICE_NAME = "content"; + + /** @hide */ + public static IContentService getContentService() { + if (sContentService != null) { + return sContentService; + } + IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME); + if (Config.LOGV) Log.v("ContentService", "default service binder = " + b); + sContentService = IContentService.Stub.asInterface(b); + if (Config.LOGV) Log.v("ContentService", "default service = " + sContentService); + return sContentService; + } + + private static IContentService sContentService; private final Context mContext; private static final String TAG = "ContentResolver"; } diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index b0288681b2b7a42f79dfd8ecfee2fcac2feffa08..6cd2c54a265cd328a585f9eb524c435a2e2859a4 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -21,6 +21,7 @@ import android.database.sqlite.SQLiteException; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; +import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Config; @@ -34,7 +35,7 @@ import java.util.ArrayList; /** * {@hide} */ -public final class ContentService extends ContentServiceNative { +public final class ContentService extends IContentService.Stub { private static final String TAG = "ContentService"; private Context mContext; private boolean mFactoryTest; @@ -73,6 +74,21 @@ public final class ContentService extends ContentServiceNative { } } + @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 content service only throws security exceptions, so let's + // log all others. + if (!(e instanceof SecurityException)) { + Log.e(TAG, "Content Service Crash", e); + } + throw e; + } + } + /*package*/ ContentService(Context context, boolean factoryTest) { mContext = context; mFactoryTest = factoryTest; @@ -204,9 +220,158 @@ public final class ContentService extends ContentServiceNative { } } + public boolean getSyncProviderAutomatically(String providerName) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, + "no permission to read the sync settings"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + return syncManager.getSyncStorageEngine().getSyncProviderAutomatically( + null, providerName); + } + } finally { + restoreCallingIdentity(identityToken); + } + return false; + } + + public void setSyncProviderAutomatically(String providerName, boolean sync) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, + "no permission to write the sync settings"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + syncManager.getSyncStorageEngine().setSyncProviderAutomatically( + null, providerName, sync); + } + } finally { + restoreCallingIdentity(identityToken); + } + } + + public boolean getListenForNetworkTickles() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, + "no permission to read the sync settings"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + return syncManager.getSyncStorageEngine().getListenForNetworkTickles(); + } + } finally { + restoreCallingIdentity(identityToken); + } + return false; + } + + public void setListenForNetworkTickles(boolean flag) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, + "no permission to write the sync settings"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + syncManager.getSyncStorageEngine().setListenForNetworkTickles(flag); + } + } finally { + restoreCallingIdentity(identityToken); + } + } + + public boolean isSyncActive(String account, String authority) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, + "no permission to read the sync stats"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + return syncManager.getSyncStorageEngine().isSyncActive( + account, authority); + } + } finally { + restoreCallingIdentity(identityToken); + } + return false; + } + + public ActiveSyncInfo getActiveSync() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, + "no permission to read the sync stats"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + return syncManager.getSyncStorageEngine().getActiveSync(); + } + } finally { + restoreCallingIdentity(identityToken); + } + return null; + } + + public SyncStatusInfo getStatusByAuthority(String authority) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, + "no permission to read the sync stats"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + return syncManager.getSyncStorageEngine().getStatusByAuthority( + authority); + } + } finally { + restoreCallingIdentity(identityToken); + } + return null; + } + + public boolean isAuthorityPending(String account, String authority) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, + "no permission to read the sync stats"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + return syncManager.getSyncStorageEngine().isAuthorityPending( + account, authority); + } + } finally { + restoreCallingIdentity(identityToken); + } + return false; + } + + public void addStatusChangeListener(int mask, ISyncStatusObserver callback) { + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + syncManager.getSyncStorageEngine().addStatusChangeListener( + mask, callback); + } + } finally { + restoreCallingIdentity(identityToken); + } + } + + public void removeStatusChangeListener(ISyncStatusObserver callback) { + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + syncManager.getSyncStorageEngine().removeStatusChangeListener( + callback); + } + } finally { + restoreCallingIdentity(identityToken); + } + } + public static IContentService main(Context context, boolean factoryTest) { ContentService service = new ContentService(context, factoryTest); - ServiceManager.addService("content", service); + ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service); return service; } diff --git a/core/java/android/content/ContentServiceNative.java b/core/java/android/content/ContentServiceNative.java deleted file mode 100644 index 364f9ee8a29d41845d9b5c80e03d09ed2bb816fe..0000000000000000000000000000000000000000 --- a/core/java/android/content/ContentServiceNative.java +++ /dev/null @@ -1,216 +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 android.content; - -import android.database.IContentObserver; -import android.net.Uri; -import android.os.Binder; -import android.os.RemoteException; -import android.os.IBinder; -import android.os.Parcel; -import android.os.ServiceManager; -import android.os.Bundle; -import android.util.Config; -import android.util.Log; - -/** - * {@hide} - */ -abstract class ContentServiceNative extends Binder implements IContentService -{ - public ContentServiceNative() - { - attachInterface(this, descriptor); - } - - /** - * Cast a Binder object into a content resolver interface, generating - * a proxy if needed. - */ - static public IContentService asInterface(IBinder obj) - { - if (obj == null) { - return null; - } - IContentService in = - (IContentService)obj.queryLocalInterface(descriptor); - if (in != null) { - return in; - } - - return new ContentServiceProxy(obj); - } - - /** - * Retrieve the system's default/global content service. - */ - static public IContentService getDefault() - { - if (gDefault != null) { - return gDefault; - } - IBinder b = ServiceManager.getService("content"); - if (Config.LOGV) Log.v("ContentService", "default service binder = " + b); - gDefault = asInterface(b); - if (Config.LOGV) Log.v("ContentService", "default service = " + gDefault); - return gDefault; - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - { - try { - switch (code) { - case 5038: { - data.readString(); // ignore the interface token that service generated - Uri uri = Uri.parse(data.readString()); - notifyChange(uri, null, false, false); - return true; - } - - case REGISTER_CONTENT_OBSERVER_TRANSACTION: { - Uri uri = Uri.CREATOR.createFromParcel(data); - boolean notifyForDescendents = data.readInt() != 0; - IContentObserver observer = IContentObserver.Stub.asInterface(data.readStrongBinder()); - registerContentObserver(uri, notifyForDescendents, observer); - return true; - } - - case UNREGISTER_CHANGE_OBSERVER_TRANSACTION: { - IContentObserver observer = IContentObserver.Stub.asInterface(data.readStrongBinder()); - unregisterContentObserver(observer); - return true; - } - - case NOTIFY_CHANGE_TRANSACTION: { - Uri uri = Uri.CREATOR.createFromParcel(data); - IContentObserver observer = IContentObserver.Stub.asInterface(data.readStrongBinder()); - boolean observerWantsSelfNotifications = data.readInt() != 0; - boolean syncToNetwork = data.readInt() != 0; - notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork); - return true; - } - - case START_SYNC_TRANSACTION: { - Uri url = null; - int hasUrl = data.readInt(); - if (hasUrl != 0) { - url = Uri.CREATOR.createFromParcel(data); - } - startSync(url, data.readBundle()); - return true; - } - - case CANCEL_SYNC_TRANSACTION: { - Uri url = null; - int hasUrl = data.readInt(); - if (hasUrl != 0) { - url = Uri.CREATOR.createFromParcel(data); - } - cancelSync(url); - return true; - } - - default: - return super.onTransact(code, data, reply, flags); - } - } catch (Exception e) { - Log.e("ContentServiceNative", "Caught exception in transact", e); - } - - return false; - } - - public IBinder asBinder() - { - return this; - } - - private static IContentService gDefault; -} - - -final class ContentServiceProxy implements IContentService -{ - public ContentServiceProxy(IBinder remote) - { - mRemote = remote; - } - - public IBinder asBinder() - { - return mRemote; - } - - public void registerContentObserver(Uri uri, boolean notifyForDescendents, - IContentObserver observer) throws RemoteException - { - Parcel data = Parcel.obtain(); - uri.writeToParcel(data, 0); - data.writeInt(notifyForDescendents ? 1 : 0); - data.writeStrongInterface(observer); - mRemote.transact(REGISTER_CONTENT_OBSERVER_TRANSACTION, data, null, 0); - data.recycle(); - } - - public void unregisterContentObserver(IContentObserver observer) throws RemoteException { - Parcel data = Parcel.obtain(); - data.writeStrongInterface(observer); - mRemote.transact(UNREGISTER_CHANGE_OBSERVER_TRANSACTION, data, null, 0); - data.recycle(); - } - - public void notifyChange(Uri uri, IContentObserver observer, - boolean observerWantsSelfNotifications, boolean syncToNetwork) - throws RemoteException { - Parcel data = Parcel.obtain(); - uri.writeToParcel(data, 0); - data.writeStrongInterface(observer); - data.writeInt(observerWantsSelfNotifications ? 1 : 0); - data.writeInt(syncToNetwork ? 1 : 0); - mRemote.transact(NOTIFY_CHANGE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); - data.recycle(); - } - - public void startSync(Uri url, Bundle extras) throws RemoteException { - Parcel data = Parcel.obtain(); - if (url == null) { - data.writeInt(0); - } else { - data.writeInt(1); - url.writeToParcel(data, 0); - } - extras.writeToParcel(data, 0); - mRemote.transact(START_SYNC_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); - data.recycle(); - } - - public void cancelSync(Uri url) throws RemoteException { - Parcel data = Parcel.obtain(); - if (url == null) { - data.writeInt(0); - } else { - data.writeInt(1); - url.writeToParcel(data, 0); - } - mRemote.transact(CANCEL_SYNC_TRANSACTION, data, null /* reply */, IBinder.FLAG_ONEWAY); - data.recycle(); - } - - private IBinder mRemote; -} - diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 600dfa40abc4a782b2d01e1918a4556b8bdc063b..f2ad2485d0e1ceb7df4f282c8b03bc42ce1c1b47 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -526,6 +526,16 @@ public abstract class Context { */ public abstract int getWallpaperDesiredMinimumHeight(); + /** + * Returns the scale in which the application will be drawn on the + * screen. This is usually 1.0f if the application supports the device's + * resolution/density. This will be 1.5f, for example, if the application + * that supports only 160 density runs on 240 density screen. + * + * @hide + */ + public abstract float getApplicationScale(); + /** * Change the current system wallpaper to a bitmap. The given bitmap is * converted to a PNG and stored as the wallpaper. On success, the intent @@ -1258,6 +1268,15 @@ public abstract class Context { */ public static final String APPWIDGET_SERVICE = "appwidget"; + /** + * Use with {@link #getSystemService} to retrieve an + * {@blink android.backup.IBackupManager IBackupManager} for communicating + * with the backup mechanism. + * + * @see #getSystemService + */ + public static final String BACKUP_SERVICE = "backup"; + /** * 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/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 36e1c340d1d98f12b2ef87c1580268f5f593b908..25b2caeb72790f3b490d52a21e466fc2930769e6 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -419,4 +419,12 @@ public class ContextWrapper extends Context { throws PackageManager.NameNotFoundException { return mBase.createPackageContext(packageName, flags); } + + /** + * @hide + */ + @Override + public float getApplicationScale() { + return mBase.getApplicationScale(); + } } diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl new file mode 100644 index 0000000000000000000000000000000000000000..8617d949c4fbe603a1391c457a2972178d5fa87b --- /dev/null +++ b/core/java/android/content/IContentService.aidl @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.content.ActiveSyncInfo; +import android.content.ISyncStatusObserver; +import android.content.SyncStatusInfo; +import android.net.Uri; +import android.os.Bundle; +import android.database.IContentObserver; + +/** + * @hide + */ +interface IContentService { + void registerContentObserver(in Uri uri, boolean notifyForDescendentsn, + IContentObserver observer); + void unregisterContentObserver(IContentObserver observer); + + void notifyChange(in Uri uri, IContentObserver observer, + boolean observerWantsSelfNotifications, boolean syncToNetwork); + + void startSync(in Uri url, in Bundle extras); + void cancelSync(in Uri uri); + + /** + * Check if the provider should be synced when a network tickle is received + * @param providerName the provider whose setting we are querying + * @return true of the provider should be synced when a network tickle is received + */ + boolean getSyncProviderAutomatically(String providerName); + + /** + * Set whether or not the provider is synced when it receives a network tickle. + * + * @param providerName the provider whose behavior is being controlled + * @param sync true if the provider should be synced when tickles are received for it + */ + void setSyncProviderAutomatically(String providerName, boolean sync); + + void setListenForNetworkTickles(boolean flag); + + boolean getListenForNetworkTickles(); + + /** + * Returns true if there is currently a sync operation for the given + * account or authority in the pending list, or actively being processed. + */ + boolean isSyncActive(String account, String authority); + + ActiveSyncInfo getActiveSync(); + + /** + * Returns the status that matches the authority. If there are multiples accounts for + * the authority, the one with the latest "lastSuccessTime" status is returned. + * @param authority the authority whose row should be selected + * @return the SyncStatusInfo for the authority, or null if none exists + */ + SyncStatusInfo getStatusByAuthority(String authority); + + /** + * Return true if the pending status is true of any matching authorities. + */ + boolean isAuthorityPending(String account, String authority); + + void addStatusChangeListener(int mask, ISyncStatusObserver callback); + + void removeStatusChangeListener(ISyncStatusObserver callback); +} diff --git a/core/java/android/content/IContentService.java b/core/java/android/content/IContentService.java deleted file mode 100644 index a3047da66c4ea73077ad85df25b310a5faa4c46f..0000000000000000000000000000000000000000 --- a/core/java/android/content/IContentService.java +++ /dev/null @@ -1,53 +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 android.content; - -import android.database.IContentObserver; -import android.net.Uri; -import android.os.RemoteException; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Bundle; - -/** - * {@hide} - */ -public interface IContentService extends IInterface -{ - public void registerContentObserver(Uri uri, boolean notifyForDescendentsn, - IContentObserver observer) throws RemoteException; - public void unregisterContentObserver(IContentObserver observer) throws RemoteException; - - public void notifyChange(Uri uri, IContentObserver observer, - boolean observerWantsSelfNotifications, boolean syncToNetwork) - throws RemoteException; - - public void startSync(Uri url, Bundle extras) throws RemoteException; - public void cancelSync(Uri uri) throws RemoteException; - - static final String SERVICE_NAME = "content"; - - /* IPC constants */ - static final String descriptor = "android.content.IContentService"; - - static final int REGISTER_CONTENT_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1; - static final int UNREGISTER_CHANGE_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 2; - static final int NOTIFY_CHANGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 3; - static final int START_SYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 4; - static final int CANCEL_SYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 5; -} - diff --git a/core/java/android/content/ISyncStatusObserver.aidl b/core/java/android/content/ISyncStatusObserver.aidl new file mode 100644 index 0000000000000000000000000000000000000000..eb2684544abf42970250a95d6070df90c7045496 --- /dev/null +++ b/core/java/android/content/ISyncStatusObserver.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +/** + * @hide + */ +oneway interface ISyncStatusObserver { + void onStatusChanged(int which); +} diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 99cf34c2ca57304fc86a3211419ea275c1fbdcde..24262f51197d5f44b1b6c2797d64fcc5176a24c8 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -508,6 +508,9 @@ import java.util.Set; *
  • {@link #ACTION_PACKAGE_DATA_CLEARED} *
  • {@link #ACTION_UID_REMOVED} *
  • {@link #ACTION_BATTERY_CHANGED} + *
  • {@link #ACTION_POWER_CONNECTED} + *
  • {@link #ACTION_POWER_DISCONNECTED} + *
  • {@link #ACTION_SHUTDOWN} * * *

    Standard Categories

    @@ -1045,6 +1048,17 @@ public class Intent implements Parcelable { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS"; + /** + * Activity Action: The user pressed the "Report" button in the crash/ANR dialog. + * This intent is delivered to the package which installed the application, usually + * the Market. + *

    Input: No data is specified. The bug report is passed in using + * an {@link #EXTRA_BUG_REPORT} field. + *

    Output: Nothing. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent broadcast actions (see action variable). @@ -1249,6 +1263,33 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW"; + /** + * Broadcast Action: External power has been connected to the device. + * This is intended for applications that wish to register specifically to this notification. + * Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to + * stay active to receive this notification. This action can be used to implement actions + * that wait until power is available to trigger. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED"; + /** + * Broadcast Action: External power has been removed from the device. + * This is intended for applications that wish to register specifically to this notification. + * Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to + * stay active to receive this notification. This action can be used to implement actions + * that wait until power is available to trigger. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED"; + /** + * Broadcast Action: Device is shutting down. + * This is broadcast when the device is being shut down (completely turned + * off, not sleeping). Once the broadcast is complete, the final shutdown + * will proceed and all unsaved data lost. Apps will not normally need + * to handle this, since the forground activity will be paused as well. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN"; /** * Broadcast Action: Indicates low memory condition on the device */ @@ -1750,6 +1791,24 @@ public class Intent implements Parcelable { * delivered. */ public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT"; + + /** + * Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing + * the bug report. + * + * @hide + */ + public static final String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT"; + + /** + * Used as a string extra field when sending an intent to PackageInstaller to install a + * package. Specifies the installer package name; this package will receive the + * {@link #ACTION_APP_ERROR} intent. + * + * @hide + */ + public static final String EXTRA_INSTALLER_PACKAGE_NAME + = "android.intent.extra.INSTALLER_PACKAGE_NAME"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- @@ -1910,7 +1969,7 @@ public class Intent implements Parcelable { /** * 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 + * is brought 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 @@ -4370,12 +4429,35 @@ public class Intent implements Parcelable { @Override public String toString() { - StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(128); + + b.append("Intent { "); + toShortString(b, true, true); + b.append(" }"); - b.append("Intent {"); - if (mAction != null) b.append(" action=").append(mAction); + return b.toString(); + } + + /** @hide */ + public String toShortString(boolean comp, boolean extras) { + StringBuilder b = new StringBuilder(128); + toShortString(b, comp, extras); + return b.toString(); + } + + /** @hide */ + public void toShortString(StringBuilder b, boolean comp, boolean extras) { + boolean first = true; + if (mAction != null) { + b.append("act=").append(mAction); + first = false; + } if (mCategories != null) { - b.append(" categories={"); + if (!first) { + b.append(' '); + } + first = false; + b.append("cat=["); Iterator i = mCategories.iterator(); boolean didone = false; while (i.hasNext()) { @@ -4383,20 +4465,48 @@ public class Intent implements Parcelable { didone = true; b.append(i.next()); } - b.append("}"); + b.append("]"); + } + if (mData != null) { + if (!first) { + b.append(' '); + } + first = false; + b.append("dat=").append(mData); + } + if (mType != null) { + if (!first) { + b.append(' '); + } + first = false; + b.append("typ=").append(mType); + } + if (mFlags != 0) { + if (!first) { + b.append(' '); + } + first = false; + b.append("flg=0x").append(Integer.toHexString(mFlags)); + } + if (comp && mComponent != null) { + if (!first) { + b.append(' '); + } + first = false; + b.append("cmp=").append(mComponent.flattenToShortString()); + } + if (extras && mExtras != null) { + if (!first) { + b.append(' '); + } + first = false; + b.append("(has extras)"); } - if (mData != null) b.append(" data=").append(mData); - if (mType != null) b.append(" type=").append(mType); - if (mFlags != 0) b.append(" flags=0x").append(Integer.toHexString(mFlags)); - if (mComponent != null) b.append(" comp=").append(mComponent.toShortString()); - if (mExtras != null) b.append(" (has extras)"); - b.append(" }"); - - return b.toString(); } public String toURI() { - StringBuilder uri = new StringBuilder(mData != null ? mData.toString() : ""); + StringBuilder uri = new StringBuilder(128); + if (mData != null) uri.append(mData.toString()); uri.append("#Intent;"); diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 9b190df84cd4dbeb412a23f894ad20a3105573e8..e5c5dc8a5e0ccf70d52c9a7bb25fa2f421983cea 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -1254,47 +1254,71 @@ public class IntentFilter implements Parcelable { } public void dump(Printer du, String prefix) { + StringBuilder sb = new StringBuilder(256); if (mActions.size() > 0) { Iterator it = mActions.iterator(); while (it.hasNext()) { - du.println(prefix + "Action: \"" + it.next() + "\""); + sb.setLength(0); + sb.append(prefix); sb.append("Action: \""); + sb.append(it.next()); sb.append("\""); + du.println(sb.toString()); } } if (mCategories != null) { Iterator it = mCategories.iterator(); while (it.hasNext()) { - du.println(prefix + "Category: \"" + it.next() + "\""); + sb.setLength(0); + sb.append(prefix); sb.append("Category: \""); + sb.append(it.next()); sb.append("\""); + du.println(sb.toString()); } } if (mDataSchemes != null) { Iterator it = mDataSchemes.iterator(); while (it.hasNext()) { - du.println(prefix + "Data Scheme: \"" + it.next() + "\""); + sb.setLength(0); + sb.append(prefix); sb.append("Scheme: \""); + sb.append(it.next()); sb.append("\""); + du.println(sb.toString()); } } if (mDataAuthorities != null) { Iterator it = mDataAuthorities.iterator(); while (it.hasNext()) { AuthorityEntry ae = it.next(); - du.println(prefix + "Data Authority: \"" + ae.mHost + "\":" - + ae.mPort + (ae.mWild ? " WILD" : "")); + sb.setLength(0); + sb.append(prefix); sb.append("Authority: \""); + sb.append(ae.mHost); sb.append("\": "); + sb.append(ae.mPort); + if (ae.mWild) sb.append(" WILD"); + du.println(sb.toString()); } } if (mDataPaths != null) { Iterator it = mDataPaths.iterator(); while (it.hasNext()) { PatternMatcher pe = it.next(); - du.println(prefix + "Data Path: \"" + pe + "\""); + sb.setLength(0); + sb.append(prefix); sb.append("Path: \""); + sb.append(pe); sb.append("\""); + du.println(sb.toString()); } } if (mDataTypes != null) { Iterator it = mDataTypes.iterator(); while (it.hasNext()) { - du.println(prefix + "Data Type: \"" + it.next() + "\""); + sb.setLength(0); + sb.append(prefix); sb.append("Type: \""); + sb.append(it.next()); sb.append("\""); + du.println(sb.toString()); } } - du.println(prefix + "mPriority=" + mPriority - + ", mHasPartialTypes=" + mHasPartialTypes); + if (mPriority != 0 || mHasPartialTypes) { + sb.setLength(0); + sb.append(prefix); sb.append("mPriority="); sb.append(mPriority); + sb.append(", mHasPartialTypes="); sb.append(mHasPartialTypes); + du.println(sb.toString()); + } } public static final Parcelable.Creator CREATOR diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 96470c3c5756c941e3d5941e5f73d6780e565985..4d2cce8818976286af62f651fa6176ef7eb22839 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -32,8 +32,6 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.database.DatabaseUtils; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; @@ -43,18 +41,13 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.Parcel; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -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; @@ -73,13 +66,12 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.Random; -import java.util.Observer; -import java.util.Observable; /** * @hide @@ -138,7 +130,6 @@ class SyncManager { volatile private PowerManager.WakeLock mHandleAlarmWakeLock; volatile private boolean mDataConnectionIsConnected = false; volatile private boolean mStorageIsLow = false; - private Sync.Settings.QueryMap mSyncSettings; private final NotificationManager mNotificationMgr; private AlarmManager mAlarmService = null; @@ -221,21 +212,18 @@ class SyncManager { } }; + private BroadcastReceiver mShutdownIntentReceiver = + new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + Log.w(TAG, "Writing sync state before shutdown..."); + getSyncStorageEngine().writeAllState(); + } + }; + private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM"; private static final String SYNC_POLL_ALARM = "android.content.syncmanager.SYNC_POLL_ALARM"; private final SyncHandler mSyncHandler; - private static final String[] SYNC_ACTIVE_PROJECTION = new String[]{ - Sync.Active.ACCOUNT, - Sync.Active.AUTHORITY, - Sync.Active.START_TIME, - }; - - private static final String[] SYNC_PENDING_PROJECTION = new String[]{ - Sync.Pending.ACCOUNT, - Sync.Pending.AUTHORITY - }; - private static final int MAX_SYNC_POLL_DELAY_SECONDS = 36 * 60 * 60; // 36 hours private static final int MIN_SYNC_POLL_DELAY_SECONDS = 24 * 60 * 60; // 24 hours @@ -269,6 +257,10 @@ class SyncManager { intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); context.registerReceiver(mStorageIntentReceiver, intentFilter); + intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); + intentFilter.setPriority(100); + context.registerReceiver(mShutdownIntentReceiver, intentFilter); + if (!factoryTest) { mNotificationMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); @@ -289,6 +281,14 @@ class SyncManager { HANDLE_SYNC_ALARM_WAKE_LOCK); mHandleAlarmWakeLock.setReferenceCounted(false); + mSyncStorageEngine.addStatusChangeListener( + SyncStorageEngine.CHANGE_SETTINGS, new ISyncStatusObserver.Stub() { + public void onStatusChanged(int which) { + // force the sync loop to run if the settings change + sendCheckAlarmsMessage(); + } + }); + if (!factoryTest) { AccountMonitorListener listener = new AccountMonitorListener() { public void onAccountsUpdated(String[] accounts) { @@ -448,20 +448,10 @@ class SyncManager { return mActiveSyncContext; } - private Sync.Settings.QueryMap getSyncSettings() { - if (mSyncSettings == null) { - mSyncSettings = new Sync.Settings.QueryMap(mContext.getContentResolver(), true, - new Handler()); - mSyncSettings.addObserver(new Observer(){ - public void update(Observable o, Object arg) { - // force the sync loop to run if the settings change - sendCheckAlarmsMessage(); - } - }); - } - return mSyncSettings; + public SyncStorageEngine getSyncStorageEngine() { + return mSyncStorageEngine; } - + private void ensureContentResolver() { if (mContentResolver == null) { mContentResolver = mContext.getContentResolver(); @@ -574,15 +564,15 @@ class SyncManager { int source; if (uploadOnly) { - source = Sync.History.SOURCE_LOCAL; + source = SyncStorageEngine.SOURCE_LOCAL; } else if (force) { - source = Sync.History.SOURCE_USER; + source = SyncStorageEngine.SOURCE_USER; } else if (url == null) { - source = Sync.History.SOURCE_POLL; + source = SyncStorageEngine.SOURCE_POLL; } else { // this isn't strictly server, since arbitrary callers can (and do) request // a non-forced two-way sync on a specific url - source = Sync.History.SOURCE_SERVER; + source = SyncStorageEngine.SOURCE_SERVER; } List names = new ArrayList(); @@ -667,9 +657,7 @@ class SyncManager { public void updateHeartbeatTime() { mHeartbeatTime = SystemClock.elapsedRealtime(); - ensureContentResolver(); - mContentResolver.notifyChange(Sync.Active.CONTENT_URI, - null /* this change wasn't made through an observer */); + mSyncStorageEngine.reportActiveChange(); } private void sendSyncAlarmMessage() { @@ -876,7 +864,7 @@ class SyncManager { final String key; long earliestRunTime; long delay; - Long rowId = null; + SyncStorageEngine.PendingOperation pendingOperation; SyncOperation(String account, int source, String authority, Bundle extras, long delay) { this.account = account; @@ -916,7 +904,7 @@ class SyncManager { sb.append(" when: ").append(earliestRunTime); sb.append(" delay: ").append(delay); sb.append(" key: {").append(key).append("}"); - if (rowId != null) sb.append(" rowId: ").append(rowId); + if (pendingOperation != null) sb.append(" pendingOperation: ").append(pendingOperation); return sb.toString(); } @@ -999,244 +987,264 @@ class SyncManager { protected void dump(FileDescriptor fd, PrintWriter pw) { StringBuilder sb = new StringBuilder(); - dumpSyncState(sb); - sb.append("\n"); + dumpSyncState(pw, sb); if (isSyncEnabled()) { - dumpSyncHistory(sb); + dumpSyncHistory(pw, sb); } - pw.println(sb.toString()); } - protected void dumpSyncState(StringBuilder sb) { - sb.append("sync enabled: ").append(isSyncEnabled()).append("\n"); - sb.append("data connected: ").append(mDataConnectionIsConnected).append("\n"); - sb.append("memory low: ").append(mStorageIsLow).append("\n"); + static String formatTime(long time) { + Time tobj = new Time(); + tobj.set(time); + return tobj.format("%Y-%m-%d %H:%M:%S"); + } + + protected void dumpSyncState(PrintWriter pw, StringBuilder sb) { + pw.print("sync enabled: "); pw.println(isSyncEnabled()); + pw.print("data connected: "); pw.println(mDataConnectionIsConnected); + pw.print("memory low: "); pw.println(mStorageIsLow); final String[] accounts = mAccounts; - sb.append("accounts: "); + pw.print("accounts: "); if (accounts != null) { - sb.append(accounts.length); + pw.println(accounts.length); } else { - sb.append("none"); + pw.println("none"); } - sb.append("\n"); final long now = SystemClock.elapsedRealtime(); - sb.append("now: ").append(now).append("\n"); - sb.append("uptime: ").append(DateUtils.formatElapsedTime(now/1000)).append(" (HH:MM:SS)\n"); - sb.append("time spent syncing : ") - .append(DateUtils.formatElapsedTime( - mSyncHandler.mSyncTimeTracker.timeSpentSyncing() / 1000)) - .append(" (HH:MM:SS), sync ") - .append(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not ") - .append("in progress").append("\n"); + pw.print("now: "); pw.println(now); + pw.print("uptime: "); pw.print(DateUtils.formatElapsedTime(now/1000)); + pw.println(" (HH:MM:SS)"); + pw.print("time spent syncing: "); + pw.print(DateUtils.formatElapsedTime( + mSyncHandler.mSyncTimeTracker.timeSpentSyncing() / 1000)); + pw.print(" (HH:MM:SS), sync "); + pw.print(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not "); + pw.println("in progress"); if (mSyncHandler.mAlarmScheduleTime != null) { - sb.append("next alarm time: ").append(mSyncHandler.mAlarmScheduleTime) - .append(" (") - .append(DateUtils.formatElapsedTime((mSyncHandler.mAlarmScheduleTime-now)/1000)) - .append(" (HH:MM:SS) from now)\n"); + pw.print("next alarm time: "); pw.print(mSyncHandler.mAlarmScheduleTime); + pw.print(" ("); + pw.print(DateUtils.formatElapsedTime((mSyncHandler.mAlarmScheduleTime-now)/1000)); + pw.println(" (HH:MM:SS) from now)"); } else { - sb.append("no alarm is scheduled (there had better not be any pending syncs)\n"); + pw.println("no alarm is scheduled (there had better not be any pending syncs)"); } - sb.append("active sync: ").append(mActiveSyncContext).append("\n"); + pw.print("active sync: "); pw.println(mActiveSyncContext); - sb.append("notification info: "); + pw.print("notification info: "); + sb.setLength(0); mSyncHandler.mSyncNotificationInfo.toString(sb); - sb.append("\n"); + pw.println(sb.toString()); synchronized (mSyncQueue) { - sb.append("sync queue: "); + pw.print("sync queue: "); + sb.setLength(0); mSyncQueue.dump(sb); - } - - Cursor c = mSyncStorageEngine.query(Sync.Active.CONTENT_URI, - SYNC_ACTIVE_PROJECTION, null, null, null); - sb.append("\n"); - try { - if (c.moveToNext()) { - final long durationInSeconds = (now - c.getLong(2)) / 1000; - sb.append("Active sync: ").append(c.getString(0)) - .append(" ").append(c.getString(1)) - .append(", duration is ") - .append(DateUtils.formatElapsedTime(durationInSeconds)).append(".\n"); - } else { - sb.append("No sync is in progress.\n"); - } - } finally { - c.close(); - } - - c = mSyncStorageEngine.query(Sync.Pending.CONTENT_URI, - SYNC_PENDING_PROJECTION, null, null, "account, authority"); - sb.append("\nPending Syncs\n"); - try { - if (c.getCount() != 0) { - dumpSyncPendingHeader(sb); - while (c.moveToNext()) { - dumpSyncPendingRow(sb, c); + pw.println(sb.toString()); + } + + ActiveSyncInfo active = mSyncStorageEngine.getActiveSync(); + if (active != null) { + SyncStorageEngine.AuthorityInfo authority + = mSyncStorageEngine.getAuthority(active.authorityId); + final long durationInSeconds = (now - active.startTime) / 1000; + pw.print("Active sync: "); + pw.print(authority != null ? authority.account : ""); + pw.print(" "); + pw.print(authority != null ? authority.authority : ""); + pw.print(", duration is "); + pw.println(DateUtils.formatElapsedTime(durationInSeconds)); + } else { + pw.println("No sync is in progress."); + } + + ArrayList ops + = mSyncStorageEngine.getPendingOperations(); + if (ops != null && ops.size() > 0) { + pw.println(); + pw.println("Pending Syncs"); + final int N = ops.size(); + for (int i=0; i processedAccounts = new HashSet(); + ArrayList statuses + = mSyncStorageEngine.getSyncStatus(); + if (statuses != null && statuses.size() > 0) { + pw.println(); + pw.println("Sync Status"); + final int N = statuses.size(); + for (int i=0; i 0) dumpSyncHistoryFooter(sb); - } finally { - c.close(); } } - private void dumpSyncHistoryHeader(StringBuilder sb, String account) { - sb.append(" Account: ").append(account).append("\n"); - sb.append(" ___________________________________________________________________________________________________________________________\n"); - sb.append(" | | num times synced | total | last success | |\n"); - sb.append(" | authority | local | poll | server | user | total | duration | source | time | result if failing |\n"); + private void dumpTimeSec(PrintWriter pw, long time) { + pw.print(time/1000); pw.print('.'); pw.print((time/100)%10); + pw.print('s'); } - - private static String[] STATUS_PROJECTION = new String[]{ - Sync.Status.ACCOUNT, // 0 - Sync.Status.AUTHORITY, // 1 - Sync.Status.NUM_SYNCS, // 2 - Sync.Status.TOTAL_ELAPSED_TIME, // 3 - Sync.Status.NUM_SOURCE_LOCAL, // 4 - Sync.Status.NUM_SOURCE_POLL, // 5 - Sync.Status.NUM_SOURCE_SERVER, // 6 - Sync.Status.NUM_SOURCE_USER, // 7 - Sync.Status.LAST_SUCCESS_SOURCE, // 8 - Sync.Status.LAST_SUCCESS_TIME, // 9 - Sync.Status.LAST_FAILURE_SOURCE, // 10 - Sync.Status.LAST_FAILURE_TIME, // 11 - Sync.Status.LAST_FAILURE_MESG // 12 - }; - - private void dumpSyncHistoryRow(StringBuilder sb, Cursor c) { - boolean hasSuccess = !c.isNull(9); - boolean hasFailure = !c.isNull(11); - Time timeSuccess = new Time(); - if (hasSuccess) timeSuccess.set(c.getLong(9)); - Time timeFailure = new Time(); - if (hasFailure) timeFailure.set(c.getLong(11)); - sb.append(String.format(" | %-15s | %5d | %5d | %6d | %5d | %5d | %8s | %7s | %19s | %19s |\n", - c.getString(1), - c.getLong(4), - c.getLong(5), - c.getLong(6), - c.getLong(7), - c.getLong(2), - DateUtils.formatElapsedTime(c.getLong(3)/1000), - hasSuccess ? Sync.History.SOURCES[c.getInt(8)] : "", - hasSuccess ? timeSuccess.format("%Y-%m-%d %H:%M:%S") : "", - hasFailure ? History.mesgToString(c.getString(12)) : "")); - } - - private void dumpSyncHistoryFooter(StringBuilder sb) { - sb.append(" |___________________________________________________________________________________________________________________________|\n"); - } - - private void dumpSyncPendingHeader(StringBuilder sb) { - sb.append(" ____________________________________________________\n"); - sb.append(" | account | authority |\n"); + + private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) { + pw.print("Success ("); pw.print(ds.successCount); + if (ds.successCount > 0) { + pw.print(" for "); dumpTimeSec(pw, ds.successTime); + pw.print(" avg="); dumpTimeSec(pw, ds.successTime/ds.successCount); + } + pw.print(") Failure ("); pw.print(ds.failureCount); + if (ds.failureCount > 0) { + pw.print(" for "); dumpTimeSec(pw, ds.failureTime); + pw.print(" avg="); dumpTimeSec(pw, ds.failureTime/ds.failureCount); + } + pw.println(")"); } - - private void dumpSyncPendingRow(StringBuilder sb, Cursor c) { - sb.append(String.format(" | %-30s | %-15s |\n", c.getString(0), c.getString(1))); - } - - private void dumpSyncPendingFooter(StringBuilder sb) { - sb.append(" |__________________________________________________|\n"); - } - - protected void dumpSyncHistory(StringBuilder sb) { - Cursor c = mSyncStorageEngine.query(Sync.History.CONTENT_URI, null, "event=?", - new String[]{String.valueOf(Sync.History.EVENT_STOP)}, - Sync.HistoryColumns.EVENT_TIME + " desc"); - try { - long numSyncsLastHour = 0, durationLastHour = 0; - long numSyncsLastDay = 0, durationLastDay = 0; - long numSyncsLastWeek = 0, durationLastWeek = 0; - long numSyncsLast4Weeks = 0, durationLast4Weeks = 0; - long numSyncsTotal = 0, durationTotal = 0; - - long now = System.currentTimeMillis(); - int indexEventTime = c.getColumnIndexOrThrow(Sync.History.EVENT_TIME); - int indexElapsedTime = c.getColumnIndexOrThrow(Sync.History.ELAPSED_TIME); - while (c.moveToNext()) { - long duration = c.getLong(indexElapsedTime); - long endTime = c.getLong(indexEventTime) + duration; - long millisSinceStart = now - endTime; - numSyncsTotal++; - durationTotal += duration; - if (millisSinceStart < MILLIS_IN_HOUR) { - numSyncsLastHour++; - durationLastHour += duration; + + protected void dumpSyncHistory(PrintWriter pw, StringBuilder sb) { + SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics(); + if (dses != null && dses[0] != null) { + pw.println(); + pw.println("Sync Statistics"); + pw.print(" Today: "); dumpDayStatistic(pw, dses[0]); + int today = dses[0].day; + int i; + SyncStorageEngine.DayStats ds; + + // Print each day in the current week. + for (i=1; i<=6 && i < dses.length; i++) { + ds = dses[i]; + if (ds == null) break; + int delta = today-ds.day; + if (delta > 6) break; + + pw.print(" Day-"); pw.print(delta); pw.print(": "); + dumpDayStatistic(pw, ds); + } + + // Aggregate all following days into weeks and print totals. + int weekDay = today; + while (i < dses.length) { + SyncStorageEngine.DayStats aggr = null; + weekDay -= 7; + while (i < dses.length) { + ds = dses[i]; + if (ds == null) { + i = dses.length; + break; + } + int delta = weekDay-ds.day; + if (delta > 6) break; + i++; + + if (aggr == null) { + aggr = new SyncStorageEngine.DayStats(weekDay); + } + aggr.successCount += ds.successCount; + aggr.successTime += ds.successTime; + aggr.failureCount += ds.failureCount; + aggr.failureTime += ds.failureTime; } - if (millisSinceStart < MILLIS_IN_DAY) { - numSyncsLastDay++; - durationLastDay += duration; + if (aggr != null) { + pw.print(" Week-"); pw.print((today-weekDay)/7); pw.print(": "); + dumpDayStatistic(pw, aggr); } - if (millisSinceStart < MILLIS_IN_WEEK) { - numSyncsLastWeek++; - durationLastWeek += duration; + } + } + + ArrayList items + = mSyncStorageEngine.getSyncHistory(); + if (items != null && items.size() > 0) { + pw.println(); + pw.println("Recent Sync History"); + final int N = items.size(); + for (int i=0; i"); + pw.print(" "); + pw.print(authority != null ? authority.authority : ""); + Time time = new Time(); + time.set(item.eventTime); + pw.print(" "); pw.print(SyncStorageEngine.SOURCES[item.source]); + pw.print(" @ "); + pw.print(formatTime(item.eventTime)); + pw.print(" for "); + dumpTimeSec(pw, item.elapsedTime); + pw.println(); + if (item.event != SyncStorageEngine.EVENT_STOP + || item.upstreamActivity !=0 + || item.downstreamActivity != 0) { + pw.print(" event="); pw.print(item.event); + pw.print(" upstreamActivity="); pw.print(item.upstreamActivity); + pw.print(" downstreamActivity="); pw.println(item.downstreamActivity); } - if (millisSinceStart < MILLIS_IN_4WEEKS) { - numSyncsLast4Weeks++; - durationLast4Weeks += duration; + if (item.mesg != null + && !SyncStorageEngine.MESG_SUCCESS.equals(item.mesg)) { + pw.print(" mesg="); pw.println(item.mesg); } } - dumpSyncIntervalHeader(sb); - dumpSyncInterval(sb, "hour", MILLIS_IN_HOUR, numSyncsLastHour, durationLastHour); - dumpSyncInterval(sb, "day", MILLIS_IN_DAY, numSyncsLastDay, durationLastDay); - dumpSyncInterval(sb, "week", MILLIS_IN_WEEK, numSyncsLastWeek, durationLastWeek); - dumpSyncInterval(sb, "4 weeks", - MILLIS_IN_4WEEKS, numSyncsLast4Weeks, durationLast4Weeks); - dumpSyncInterval(sb, "total", 0, numSyncsTotal, durationTotal); - dumpSyncIntervalFooter(sb); - } finally { - c.close(); - } - } - - private void dumpSyncIntervalHeader(StringBuilder sb) { - sb.append("Sync Stats\n"); - sb.append(" ___________________________________________________________\n"); - sb.append(" | | | duration in sec | |\n"); - sb.append(" | interval | count | average | total | % of interval |\n"); - } - - private void dumpSyncInterval(StringBuilder sb, String label, - long interval, long numSyncs, long duration) { - sb.append(String.format(" | %-8s | %6d | %8.1f | %8.1f", - label, numSyncs, ((float)duration/numSyncs)/1000, (float)duration/1000)); - if (interval > 0) { - sb.append(String.format(" | %13.2f |\n", ((float)duration/interval)*100.0)); - } else { - sb.append(String.format(" | %13s |\n", "na")); } } - private void dumpSyncIntervalFooter(StringBuilder sb) { - sb.append(" |_________________________________________________________|\n"); - } - /** * A helper object to keep track of the time we have spent syncing since the last boot */ @@ -1461,7 +1469,6 @@ class SyncManager { // found that is runnable (not disabled, etc). If that one is ready to run then // start it, otherwise just get out. SyncOperation syncOperation; - final Sync.Settings.QueryMap syncSettings = getSyncSettings(); final ConnectivityManager connManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); final boolean backgroundDataSetting = connManager.getBackgroundDataSetting(); @@ -1488,9 +1495,9 @@ class SyncManager { final boolean force = syncOperation.extras.getBoolean( ContentResolver.SYNC_EXTRAS_FORCE, false); if (!force && (!backgroundDataSetting - || !syncSettings.getListenForNetworkTickles() - || !syncSettings.getSyncProviderAutomatically( - syncOperation.authority))) { + || !mSyncStorageEngine.getListenForNetworkTickles() + || !mSyncStorageEngine.getSyncProviderAutomatically( + null, syncOperation.authority))) { if (isLoggable) { Log.v(TAG, "runStateIdle: sync off, dropping " + syncOperation); } @@ -1616,7 +1623,7 @@ class SyncManager { if (isLoggable) { Log.v(TAG, "finished sync operation " + syncOperation); } - historyMessage = History.MESG_SUCCESS; + historyMessage = SyncStorageEngine.MESG_SUCCESS; // TODO: set these correctly when the SyncResult is extended to include it downstreamActivity = 0; upstreamActivity = 0; @@ -1640,7 +1647,7 @@ class SyncManager { } catch (RemoteException e) { // we don't need to retry this in this case } - historyMessage = History.MESG_CANCELED; + historyMessage = SyncStorageEngine.MESG_CANCELED; downstreamActivity = 0; upstreamActivity = 0; } @@ -1675,14 +1682,22 @@ class SyncManager { * If SyncResult.error() is true then it is safe to call this. */ private int syncResultToErrorNumber(SyncResult syncResult) { - if (syncResult.syncAlreadyInProgress) return History.ERROR_SYNC_ALREADY_IN_PROGRESS; - if (syncResult.stats.numAuthExceptions > 0) return History.ERROR_AUTHENTICATION; - if (syncResult.stats.numIoExceptions > 0) return History.ERROR_IO; - if (syncResult.stats.numParseExceptions > 0) return History.ERROR_PARSE; - if (syncResult.stats.numConflictDetectedExceptions > 0) return History.ERROR_CONFLICT; - if (syncResult.tooManyDeletions) return History.ERROR_TOO_MANY_DELETIONS; - if (syncResult.tooManyRetries) return History.ERROR_TOO_MANY_RETRIES; - if (syncResult.databaseError) return History.ERROR_INTERNAL; + if (syncResult.syncAlreadyInProgress) + return SyncStorageEngine.ERROR_SYNC_ALREADY_IN_PROGRESS; + if (syncResult.stats.numAuthExceptions > 0) + return SyncStorageEngine.ERROR_AUTHENTICATION; + if (syncResult.stats.numIoExceptions > 0) + return SyncStorageEngine.ERROR_IO; + if (syncResult.stats.numParseExceptions > 0) + return SyncStorageEngine.ERROR_PARSE; + if (syncResult.stats.numConflictDetectedExceptions > 0) + return SyncStorageEngine.ERROR_CONFLICT; + if (syncResult.tooManyDeletions) + return SyncStorageEngine.ERROR_TOO_MANY_DELETIONS; + if (syncResult.tooManyRetries) + return SyncStorageEngine.ERROR_TOO_MANY_RETRIES; + if (syncResult.databaseError) + return SyncStorageEngine.ERROR_INTERNAL; throw new IllegalStateException("we are not in an error state, " + syncResult); } @@ -1904,7 +1919,8 @@ class SyncManager { final int source = syncOperation.syncSource; final long now = System.currentTimeMillis(); - EventLog.writeEvent(2720, syncOperation.authority, Sync.History.EVENT_START, source); + EventLog.writeEvent(2720, syncOperation.authority, + SyncStorageEngine.EVENT_START, source); return mSyncStorageEngine.insertStartSyncEvent( syncOperation.account, syncOperation.authority, now, source); @@ -1912,7 +1928,8 @@ class SyncManager { public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage, int upstreamActivity, int downstreamActivity, long elapsedTime) { - EventLog.writeEvent(2720, syncOperation.authority, Sync.History.EVENT_STOP, syncOperation.syncSource); + EventLog.writeEvent(2720, syncOperation.authority, + SyncStorageEngine.EVENT_STOP, syncOperation.syncSource); mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime, resultMessage, downstreamActivity, upstreamActivity); @@ -1921,18 +1938,6 @@ class SyncManager { static class SyncQueue { private SyncStorageEngine mSyncStorageEngine; - private final String[] COLUMNS = new String[]{ - "_id", - "authority", - "account", - "extras", - "source" - }; - private static final int COLUMN_ID = 0; - private static final int COLUMN_AUTHORITY = 1; - private static final int COLUMN_ACCOUNT = 2; - private static final int COLUMN_EXTRAS = 3; - private static final int COLUMN_SOURCE = 4; private static final boolean DEBUG_CHECK_DATA_CONSISTENCY = false; @@ -1946,25 +1951,28 @@ class SyncManager { public SyncQueue(SyncStorageEngine syncStorageEngine) { mSyncStorageEngine = syncStorageEngine; - Cursor cursor = mSyncStorageEngine.getPendingSyncsCursor(COLUMNS); - try { - while (cursor.moveToNext()) { - add(cursorToOperation(cursor), - true /* this is being added from the database */); - } - } finally { - cursor.close(); - if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(true /* check the DB */); - } + ArrayList ops + = mSyncStorageEngine.getPendingOperations(); + final int N = ops.size(); + for (int i=0; i= existingOperation.earliestRunTime) { - if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(!fromDatabase); + if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(pop == null); return false; } @@ -2004,26 +2012,17 @@ class SyncManager { removeByKey(operationKey); } - if (operation.rowId == null) { - byte[] extrasData = null; - Parcel parcel = Parcel.obtain(); - try { - operation.extras.writeToParcel(parcel, 0); - extrasData = parcel.marshall(); - } finally { - parcel.recycle(); - } - ContentValues values = new ContentValues(); - values.put("account", operation.account); - values.put("authority", operation.authority); - values.put("source", operation.syncSource); - values.put("extras", extrasData); - Uri pendingUri = mSyncStorageEngine.insertIntoPending(values); - operation.rowId = pendingUri == null ? null : ContentUris.parseId(pendingUri); - if (operation.rowId == null) { + operation.pendingOperation = pop; + if (operation.pendingOperation == null) { + pop = new SyncStorageEngine.PendingOperation( + operation.account, operation.syncSource, + operation.authority, operation.extras); + pop = mSyncStorageEngine.insertIntoPending(pop); + if (pop == null) { throw new IllegalStateException("error adding pending sync operation " + operation); } + operation.pendingOperation = pop; } if (DEBUG_CHECK_DATA_CONSISTENCY) { @@ -2033,7 +2032,7 @@ class SyncManager { } mOpsByKey.put(operationKey, operation); mOpsByWhen.add(operation); - if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(!fromDatabase); + if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(pop == null); return true; } @@ -2045,7 +2044,7 @@ class SyncManager { "unable to find " + operationToRemove + " in mOpsByWhen"); } - if (mSyncStorageEngine.deleteFromPending(operationToRemove.rowId) != 1) { + if (!mSyncStorageEngine.deleteFromPending(operationToRemove.pendingOperation)) { throw new IllegalStateException("unable to find pending row for " + operationToRemove); } @@ -2065,7 +2064,7 @@ class SyncManager { throw new IllegalStateException("unable to find " + operation + " in mOpsByKey"); } - if (mSyncStorageEngine.deleteFromPending(operation.rowId) != 1) { + if (!mSyncStorageEngine.deleteFromPending(operation.pendingOperation)) { throw new IllegalStateException("unable to find pending row for " + operation); } @@ -2087,7 +2086,7 @@ class SyncManager { "unable to find " + syncOperation + " in mOpsByWhen"); } - if (mSyncStorageEngine.deleteFromPending(syncOperation.rowId) != 1) { + if (!mSyncStorageEngine.deleteFromPending(syncOperation.pendingOperation)) { throw new IllegalStateException("unable to find pending row for " + syncOperation); } @@ -2128,48 +2127,29 @@ class SyncManager { } if (checkDatabase) { - // check that the DB contains the same rows as the in-memory data structures - Cursor cursor = mSyncStorageEngine.getPendingSyncsCursor(COLUMNS); - try { - if (mOpsByKey.size() != cursor.getCount()) { - StringBuilder sb = new StringBuilder(); - DatabaseUtils.dumpCursor(cursor, sb); + final int N = mSyncStorageEngine.getPendingOperationCount(); + if (mOpsByKey.size() != N) { + ArrayList ops + = mSyncStorageEngine.getPendingOperations(); + StringBuilder sb = new StringBuilder(); + for (int i=0; i CREATOR = new Creator() { + public SyncStatusInfo createFromParcel(Parcel in) { + return new SyncStatusInfo(in); + } + + public SyncStatusInfo[] newArray(int size) { + return new SyncStatusInfo[size]; + } + }; +} \ No newline at end of file diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 282f6e71db7053a3d2937959f68c89ee9fa8d016..9c25e73b0cf3d10348d7f3a549ae624f5fa777c8 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -1,125 +1,282 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.content; -import android.Manifest; +import com.android.internal.os.AtomicFile; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FastXmlSerializer; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import android.database.Cursor; -import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.provider.Sync; -import android.text.TextUtils; -import android.util.Config; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.os.Parcel; +import android.os.RemoteCallbackList; +import android.os.RemoteException; import android.util.Log; +import android.util.SparseArray; +import android.util.Xml; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.util.ArrayList; +import java.util.Calendar; import java.util.HashMap; -import java.util.HashSet; +import java.util.Iterator; +import java.util.TimeZone; /** - * ContentProvider that tracks the sync data and overall sync + * Singleton that tracks the sync data and overall sync * history on the device. * * @hide */ -public class SyncStorageEngine { +public class SyncStorageEngine extends Handler { private static final String TAG = "SyncManager"; + private static final boolean DEBUG = false; + private static final boolean DEBUG_FILE = false; + + // @VisibleForTesting + static final long MILLIS_IN_4WEEKS = 1000L * 60 * 60 * 24 * 7 * 4; - private static final String DATABASE_NAME = "syncmanager.db"; - private static final int DATABASE_VERSION = 10; + /** Enum value for a sync start event. */ + public static final int EVENT_START = 0; - private static final int STATS = 1; - private static final int STATS_ID = 2; - private static final int HISTORY = 3; - private static final int HISTORY_ID = 4; - private static final int SETTINGS = 5; - private static final int PENDING = 7; - private static final int ACTIVE = 8; - private static final int STATUS = 9; + /** Enum value for a sync stop event. */ + public static final int EVENT_STOP = 1; - private static final UriMatcher sURLMatcher = - new UriMatcher(UriMatcher.NO_MATCH); + // TODO: i18n -- grab these out of resources. + /** String names for the sync event types. */ + public static final String[] EVENTS = { "START", "STOP" }; - private static final HashMap HISTORY_PROJECTION_MAP; - private static final HashMap PENDING_PROJECTION_MAP; - private static final HashMap ACTIVE_PROJECTION_MAP; - private static final HashMap STATUS_PROJECTION_MAP; + /** Enum value for a server-initiated sync. */ + public static final int SOURCE_SERVER = 0; - private final Context mContext; - private final SQLiteOpenHelper mOpenHelper; - private static SyncStorageEngine sSyncStorageEngine = null; - - static { - sURLMatcher.addURI("sync", "stats", STATS); - sURLMatcher.addURI("sync", "stats/#", STATS_ID); - sURLMatcher.addURI("sync", "history", HISTORY); - sURLMatcher.addURI("sync", "history/#", HISTORY_ID); - sURLMatcher.addURI("sync", "settings", SETTINGS); - sURLMatcher.addURI("sync", "status", STATUS); - sURLMatcher.addURI("sync", "active", ACTIVE); - sURLMatcher.addURI("sync", "pending", PENDING); - - HashMap map; - PENDING_PROJECTION_MAP = map = new HashMap(); - map.put(Sync.History._ID, Sync.History._ID); - map.put(Sync.History.ACCOUNT, Sync.History.ACCOUNT); - map.put(Sync.History.AUTHORITY, Sync.History.AUTHORITY); - - ACTIVE_PROJECTION_MAP = map = new HashMap(); - map.put(Sync.History._ID, Sync.History._ID); - map.put(Sync.History.ACCOUNT, Sync.History.ACCOUNT); - map.put(Sync.History.AUTHORITY, Sync.History.AUTHORITY); - map.put("startTime", "startTime"); - - HISTORY_PROJECTION_MAP = map = new HashMap(); - map.put(Sync.History._ID, "history._id as _id"); - map.put(Sync.History.ACCOUNT, "stats.account as account"); - map.put(Sync.History.AUTHORITY, "stats.authority as authority"); - map.put(Sync.History.EVENT, Sync.History.EVENT); - map.put(Sync.History.EVENT_TIME, Sync.History.EVENT_TIME); - map.put(Sync.History.ELAPSED_TIME, Sync.History.ELAPSED_TIME); - map.put(Sync.History.SOURCE, Sync.History.SOURCE); - map.put(Sync.History.UPSTREAM_ACTIVITY, Sync.History.UPSTREAM_ACTIVITY); - map.put(Sync.History.DOWNSTREAM_ACTIVITY, Sync.History.DOWNSTREAM_ACTIVITY); - map.put(Sync.History.MESG, Sync.History.MESG); - - STATUS_PROJECTION_MAP = map = new HashMap(); - map.put(Sync.Status._ID, "status._id as _id"); - map.put(Sync.Status.ACCOUNT, "stats.account as account"); - map.put(Sync.Status.AUTHORITY, "stats.authority as authority"); - map.put(Sync.Status.TOTAL_ELAPSED_TIME, Sync.Status.TOTAL_ELAPSED_TIME); - map.put(Sync.Status.NUM_SYNCS, Sync.Status.NUM_SYNCS); - map.put(Sync.Status.NUM_SOURCE_LOCAL, Sync.Status.NUM_SOURCE_LOCAL); - map.put(Sync.Status.NUM_SOURCE_POLL, Sync.Status.NUM_SOURCE_POLL); - map.put(Sync.Status.NUM_SOURCE_SERVER, Sync.Status.NUM_SOURCE_SERVER); - map.put(Sync.Status.NUM_SOURCE_USER, Sync.Status.NUM_SOURCE_USER); - map.put(Sync.Status.LAST_SUCCESS_SOURCE, Sync.Status.LAST_SUCCESS_SOURCE); - map.put(Sync.Status.LAST_SUCCESS_TIME, Sync.Status.LAST_SUCCESS_TIME); - map.put(Sync.Status.LAST_FAILURE_SOURCE, Sync.Status.LAST_FAILURE_SOURCE); - map.put(Sync.Status.LAST_FAILURE_TIME, Sync.Status.LAST_FAILURE_TIME); - map.put(Sync.Status.LAST_FAILURE_MESG, Sync.Status.LAST_FAILURE_MESG); - map.put(Sync.Status.PENDING, Sync.Status.PENDING); - } - - private static final String[] STATS_ACCOUNT_PROJECTION = - new String[] { Sync.Stats.ACCOUNT }; - - private static final int MAX_HISTORY_EVENTS_TO_KEEP = 5000; - - private static final String SELECT_INITIAL_FAILURE_TIME_QUERY_STRING = "" - + "SELECT min(a) " - + "FROM (" - + " SELECT initialFailureTime AS a " - + " FROM status " - + " WHERE stats_id=? AND a IS NOT NULL " - + " UNION " - + " SELECT ? AS a" - + " )"; + /** Enum value for a local-initiated sync. */ + public static final int SOURCE_LOCAL = 1; + /** + * Enum value for a poll-based sync (e.g., upon connection to + * network) + */ + public static final int SOURCE_POLL = 2; + + /** Enum value for a user-initiated sync. */ + public static final int SOURCE_USER = 3; + + // TODO: i18n -- grab these out of resources. + /** String names for the sync source types. */ + public static final String[] SOURCES = { "SERVER", + "LOCAL", + "POLL", + "USER" }; + + // Error types + public static final int ERROR_SYNC_ALREADY_IN_PROGRESS = 1; + public static final int ERROR_AUTHENTICATION = 2; + public static final int ERROR_IO = 3; + public static final int ERROR_PARSE = 4; + public static final int ERROR_CONFLICT = 5; + public static final int ERROR_TOO_MANY_DELETIONS = 6; + public static final int ERROR_TOO_MANY_RETRIES = 7; + public static final int ERROR_INTERNAL = 8; + + // The MESG column will contain one of these or one of the Error types. + public static final String MESG_SUCCESS = "success"; + public static final String MESG_CANCELED = "canceled"; + + public static final int CHANGE_SETTINGS = 1<<0; + public static final int CHANGE_PENDING = 1<<1; + public static final int CHANGE_ACTIVE = 1<<2; + public static final int CHANGE_STATUS = 1<<3; + public static final int CHANGE_ALL = 0x7fffffff; + + public static final int MAX_HISTORY = 15; + + private static final int MSG_WRITE_STATUS = 1; + private static final long WRITE_STATUS_DELAY = 1000*60*10; // 10 minutes + + private static final int MSG_WRITE_STATISTICS = 2; + private static final long WRITE_STATISTICS_DELAY = 1000*60*30; // 1/2 hour + + public static class PendingOperation { + final String account; + final int syncSource; + final String authority; + final Bundle extras; // note: read-only. + + int authorityId; + byte[] flatExtras; + + PendingOperation(String account, int source, + String authority, Bundle extras) { + this.account = account; + this.syncSource = source; + this.authority = authority; + this.extras = extras != null ? new Bundle(extras) : extras; + this.authorityId = -1; + } + PendingOperation(PendingOperation other) { + this.account = other.account; + this.syncSource = other.syncSource; + this.authority = other.authority; + this.extras = other.extras; + this.authorityId = other.authorityId; + } + } + + static class AccountInfo { + final String account; + final HashMap authorities = + new HashMap(); + + AccountInfo(String account) { + this.account = account; + } + } + + public static class AuthorityInfo { + final String account; + final String authority; + final int ident; + boolean enabled; + + AuthorityInfo(String account, String authority, int ident) { + this.account = account; + this.authority = authority; + this.ident = ident; + enabled = true; + } + } + + public static class SyncHistoryItem { + int authorityId; + int historyId; + long eventTime; + long elapsedTime; + int source; + int event; + long upstreamActivity; + long downstreamActivity; + String mesg; + } + + public static class DayStats { + public final int day; + public int successCount; + public long successTime; + public int failureCount; + public long failureTime; + + public DayStats(int day) { + this.day = day; + } + } + + // Primary list of all syncable authorities. Also our global lock. + private final SparseArray mAuthorities = + new SparseArray(); + + private final HashMap mAccounts = + new HashMap(); + + private final ArrayList mPendingOperations = + new ArrayList(); + + private ActiveSyncInfo mActiveSync; + + private final SparseArray mSyncStatus = + new SparseArray(); + + private final ArrayList mSyncHistory = + new ArrayList(); + + private final RemoteCallbackList mChangeListeners + = new RemoteCallbackList(); + + // We keep 4 weeks of stats. + private final DayStats[] mDayStats = new DayStats[7*4]; + private final Calendar mCal; + private int mYear; + private int mYearInDays; + + private final Context mContext; + private static volatile SyncStorageEngine sSyncStorageEngine = null; + + /** + * This file contains the core engine state: all accounts and the + * settings for them. It must never be lost, and should be changed + * infrequently, so it is stored as an XML file. + */ + private final AtomicFile mAccountInfoFile; + + /** + * This file contains the current sync status. We would like to retain + * it across boots, but its loss is not the end of the world, so we store + * this information as binary data. + */ + private final AtomicFile mStatusFile; + + /** + * This file contains sync statistics. This is purely debugging information + * so is written infrequently and can be thrown away at any time. + */ + private final AtomicFile mStatisticsFile; + + /** + * This file contains the pending sync operations. It is a binary file, + * which must be updated every time an operation is added or removed, + * so we have special handling of it. + */ + private final AtomicFile mPendingFile; + private static final int PENDING_FINISH_TO_WRITE = 4; + private int mNumPendingFinished = 0; + + private int mNextHistoryId = 0; + private boolean mListenForTickles = true; + private SyncStorageEngine(Context context) { mContext = context; - mOpenHelper = new SyncStorageEngine.DatabaseHelper(context); sSyncStorageEngine = this; + + mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0")); + + File dataDir = Environment.getDataDirectory(); + File systemDir = new File(dataDir, "system"); + File syncDir = new File(systemDir, "sync"); + mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); + mStatusFile = new AtomicFile(new File(syncDir, "status.bin")); + mPendingFile = new AtomicFile(new File(syncDir, "pending.bin")); + mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin")); + + readAccountInfoLocked(); + readStatusLocked(); + readPendingOperationsLocked(); + readStatisticsLocked(); + readLegacyAccountInfoLocked(); } public static SyncStorageEngine newTestInstance(Context context) { @@ -140,619 +297,1263 @@ public class SyncStorageEngine { return sSyncStorageEngine; } - private class DatabaseHelper extends SQLiteOpenHelper { - DatabaseHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE pending (" - + "_id INTEGER PRIMARY KEY," - + "authority TEXT NOT NULL," - + "account TEXT NOT NULL," - + "extras BLOB NOT NULL," - + "source INTEGER NOT NULL" - + ");"); - - db.execSQL("CREATE TABLE stats (" + - "_id INTEGER PRIMARY KEY," + - "account TEXT, " + - "authority TEXT, " + - "syncdata TEXT, " + - "UNIQUE (account, authority)" + - ");"); - - db.execSQL("CREATE TABLE history (" + - "_id INTEGER PRIMARY KEY," + - "stats_id INTEGER," + - "eventTime INTEGER," + - "elapsedTime INTEGER," + - "source INTEGER," + - "event INTEGER," + - "upstreamActivity INTEGER," + - "downstreamActivity INTEGER," + - "mesg TEXT);"); - - db.execSQL("CREATE TABLE status (" - + "_id INTEGER PRIMARY KEY," - + "stats_id INTEGER NOT NULL," - + "totalElapsedTime INTEGER NOT NULL DEFAULT 0," - + "numSyncs INTEGER NOT NULL DEFAULT 0," - + "numSourcePoll INTEGER NOT NULL DEFAULT 0," - + "numSourceServer INTEGER NOT NULL DEFAULT 0," - + "numSourceLocal INTEGER NOT NULL DEFAULT 0," - + "numSourceUser INTEGER NOT NULL DEFAULT 0," - + "lastSuccessTime INTEGER," - + "lastSuccessSource INTEGER," - + "lastFailureTime INTEGER," - + "lastFailureSource INTEGER," - + "lastFailureMesg STRING," - + "initialFailureTime INTEGER," - + "pending INTEGER NOT NULL DEFAULT 0);"); - - db.execSQL("CREATE TABLE active (" - + "_id INTEGER PRIMARY KEY," - + "authority TEXT," - + "account TEXT," - + "startTime INTEGER);"); - - db.execSQL("CREATE INDEX historyEventTime ON history (eventTime)"); - - db.execSQL("CREATE TABLE settings (" + - "name TEXT PRIMARY KEY," + - "value TEXT);"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion == 9 && newVersion == 10) { - Log.w(TAG, "Upgrading database from version " + oldVersion + " to " - + newVersion + ", which will preserve old data"); - db.execSQL("ALTER TABLE status ADD COLUMN initialFailureTime INTEGER"); - return; + @Override public void handleMessage(Message msg) { + if (msg.what == MSG_WRITE_STATUS) { + synchronized (mAccounts) { + writeStatusLocked(); + } + } else if (msg.what == MSG_WRITE_STATISTICS) { + synchronized (mAccounts) { + writeStatisticsLocked(); } - - Log.w(TAG, "Upgrading database from version " + oldVersion + " to " - + newVersion + ", which will destroy all old data"); - db.execSQL("DROP TABLE IF EXISTS pending"); - db.execSQL("DROP TABLE IF EXISTS stats"); - db.execSQL("DROP TABLE IF EXISTS history"); - db.execSQL("DROP TABLE IF EXISTS settings"); - db.execSQL("DROP TABLE IF EXISTS active"); - db.execSQL("DROP TABLE IF EXISTS status"); - onCreate(db); } - - @Override - public void onOpen(SQLiteDatabase db) { - if (!db.isReadOnly()) { - db.delete("active", null, null); - db.insert("active", "account", null); + } + + public void addStatusChangeListener(int mask, ISyncStatusObserver callback) { + synchronized (mAuthorities) { + mChangeListeners.register(callback, mask); + } + } + + public void removeStatusChangeListener(ISyncStatusObserver callback) { + synchronized (mAuthorities) { + mChangeListeners.unregister(callback); + } + } + + private void reportChange(int which) { + ArrayList reports = null; + synchronized (mAuthorities) { + int i = mChangeListeners.beginBroadcast(); + while (i > 0) { + i--; + Integer mask = (Integer)mChangeListeners.getBroadcastCookie(i); + if ((which & mask.intValue()) == 0) { + continue; + } + if (reports == null) { + reports = new ArrayList(i); + } + reports.add(mChangeListeners.getBroadcastItem(i)); + } + } + + if (DEBUG) Log.v(TAG, "reportChange " + which + " to: " + reports); + + if (reports != null) { + int i = reports.size(); + while (i > 0) { + i--; + try { + reports.get(i).onStatusChanged(which); + } catch (RemoteException e) { + // The remote callback list will take care of this for us. + } + } + } + } + + public boolean getSyncProviderAutomatically(String account, String providerName) { + synchronized (mAuthorities) { + if (account != null) { + AuthorityInfo authority = getAuthorityLocked(account, providerName, + "getSyncProviderAutomatically"); + return authority != null ? authority.enabled : false; + } + + int i = mAuthorities.size(); + while (i > 0) { + i--; + AuthorityInfo authority = mAuthorities.get(i); + if (authority.authority.equals(providerName) + && authority.enabled) { + return true; + } } + return false; } } - protected void doDatabaseCleanup(String[] accounts) { - HashSet currentAccounts = new HashSet(); - for (String account : accounts) currentAccounts.add(account); - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - Cursor cursor = db.query("stats", STATS_ACCOUNT_PROJECTION, - null /* where */, null /* where args */, Sync.Stats.ACCOUNT, - null /* having */, null /* order by */); - try { - while (cursor.moveToNext()) { - String account = cursor.getString(0); - if (TextUtils.isEmpty(account)) { - continue; + public void setSyncProviderAutomatically(String account, String providerName, boolean sync) { + synchronized (mAuthorities) { + if (account != null) { + AuthorityInfo authority = getAuthorityLocked(account, providerName, + "setSyncProviderAutomatically"); + if (authority != null) { + authority.enabled = sync; } - if (!currentAccounts.contains(account)) { - String where = Sync.Stats.ACCOUNT + "=?"; - int numDeleted; - numDeleted = db.delete("stats", where, new String[]{account}); - if (Config.LOGD) { - Log.d(TAG, "deleted " + numDeleted - + " records from stats table" - + " for account " + account); + } else { + int i = mAuthorities.size(); + while (i > 0) { + i--; + AuthorityInfo authority = mAuthorities.get(i); + if (authority.authority.equals(providerName)) { + authority.enabled = sync; } } } - } finally { - cursor.close(); + writeAccountInfoLocked(); } + + reportChange(CHANGE_SETTINGS); } - protected void setActiveSync(SyncManager.ActiveSyncContext activeSyncContext) { - if (activeSyncContext != null) { - updateActiveSync(activeSyncContext.mSyncOperation.account, - activeSyncContext.mSyncOperation.authority, activeSyncContext.mStartTime); - } else { - // we indicate that the sync is not active by passing null for all the parameters - updateActiveSync(null, null, null); + public void setListenForNetworkTickles(boolean flag) { + synchronized (mAuthorities) { + mListenForTickles = flag; + writeAccountInfoLocked(); } + reportChange(CHANGE_SETTINGS); } - private int updateActiveSync(String account, String authority, Long startTime) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - ContentValues values = new ContentValues(); - values.put("account", account); - values.put("authority", authority); - values.put("startTime", startTime); - int numChanges = db.update("active", values, null, null); - if (numChanges > 0) { - mContext.getContentResolver().notifyChange(Sync.Active.CONTENT_URI, - null /* this change wasn't made through an observer */); + public boolean getListenForNetworkTickles() { + synchronized (mAuthorities) { + return mListenForTickles; } - return numChanges; } - - /** - * Implements the {@link ContentProvider#query} method - */ - 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); - String groupBy = null; - switch (match) { - case STATS: - qb.setTables("stats"); - break; - case STATS_ID: - qb.setTables("stats"); - qb.appendWhere("_id="); - qb.appendWhere(url.getPathSegments().get(1)); - break; - case HISTORY: - // join the stats and history tables, so the caller can get - // the account and authority information as part of this query. - qb.setTables("stats, history"); - qb.setProjectionMap(HISTORY_PROJECTION_MAP); - qb.appendWhere("stats._id = history.stats_id"); - break; - case ACTIVE: - qb.setTables("active"); - qb.setProjectionMap(ACTIVE_PROJECTION_MAP); - qb.appendWhere("account is not null"); - break; - case PENDING: - qb.setTables("pending"); - qb.setProjectionMap(PENDING_PROJECTION_MAP); - groupBy = "account, authority"; - break; - case STATUS: - // join the stats and status tables, so the caller can get - // the account and authority information as part of this query. - qb.setTables("stats, status"); - qb.setProjectionMap(STATUS_PROJECTION_MAP); - qb.appendWhere("stats._id = status.stats_id"); - break; - case HISTORY_ID: - // join the stats and history tables, so the caller can get - // the account and authority information as part of this query. - qb.setTables("stats, history"); - qb.setProjectionMap(HISTORY_PROJECTION_MAP); - qb.appendWhere("stats._id = history.stats_id"); - qb.appendWhere("AND history._id="); - qb.appendWhere(url.getPathSegments().get(1)); - break; - case SETTINGS: - qb.setTables("settings"); - break; - default: - throw new IllegalArgumentException("Unknown URL " + url); - } - - if (match == SETTINGS) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, - "no permission to read the sync settings"); - } else { - mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, - "no permission to read the sync stats"); - } - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - Cursor c = qb.query(db, projectionIn, selection, selectionArgs, groupBy, null, sort); - c.setNotificationUri(mContext.getContentResolver(), url); - return c; + + public AuthorityInfo getAuthority(String account, String authority) { + synchronized (mAuthorities) { + return getAuthorityLocked(account, authority, null); + } } - + + public AuthorityInfo getAuthority(int authorityId) { + synchronized (mAuthorities) { + return mAuthorities.get(authorityId); + } + } + /** - * Implements the {@link ContentProvider#insert} method - * @param callerIsTheProvider true if this is being called via the - * {@link ContentProvider#insert} in method rather than directly. - * @throws UnsupportedOperationException if callerIsTheProvider is true and the url isn't - * for the Settings table. + * Returns true if there is currently a sync operation for the given + * account or authority in the pending list, or actively being processed. */ - public Uri insert(boolean callerIsTheProvider, Uri url, ContentValues values) { - String table; - long rowID; - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - final int match = sURLMatcher.match(url); - checkCaller(callerIsTheProvider, match); - switch (match) { - case SETTINGS: - mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, - "no permission to write the sync settings"); - table = "settings"; - rowID = db.replace(table, null, values); - break; - default: - throw new IllegalArgumentException("Unknown URL " + url); + public boolean isSyncActive(String account, String authority) { + synchronized (mAuthorities) { + int i = mPendingOperations.size(); + while (i > 0) { + i--; + // TODO(fredq): this probably shouldn't be considering + // pending operations. + PendingOperation op = mPendingOperations.get(i); + if (op.account.equals(account) && op.authority.equals(authority)) { + return true; + } + } + + if (mActiveSync != null) { + AuthorityInfo ainfo = getAuthority(mActiveSync.authorityId); + if (ainfo != null && ainfo.account.equals(account) + && ainfo.authority.equals(authority)) { + return true; + } + } } - - - if (rowID > 0) { - mContext.getContentResolver().notifyChange(url, null /* observer */); - return Uri.parse("content://sync/" + table + "/" + rowID); + + return false; + } + + public PendingOperation insertIntoPending(PendingOperation op) { + synchronized (mAuthorities) { + if (DEBUG) Log.v(TAG, "insertIntoPending: account=" + op.account + + " auth=" + op.authority + + " src=" + op.syncSource + + " extras=" + op.extras); + + AuthorityInfo authority = getOrCreateAuthorityLocked(op.account, + op.authority, + -1 /* desired identifier */, + true /* write accounts to storage */); + if (authority == null) { + return null; + } + + op = new PendingOperation(op); + op.authorityId = authority.ident; + mPendingOperations.add(op); + appendPendingOperationLocked(op); + + SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident); + status.pending = true; } + + reportChange(CHANGE_PENDING); + return op; + } - return null; + public boolean deleteFromPending(PendingOperation op) { + boolean res = false; + synchronized (mAuthorities) { + if (DEBUG) Log.v(TAG, "deleteFromPending: account=" + op.account + + " auth=" + op.authority + + " src=" + op.syncSource + + " extras=" + op.extras); + if (mPendingOperations.remove(op)) { + if (mPendingOperations.size() == 0 + || mNumPendingFinished >= PENDING_FINISH_TO_WRITE) { + writePendingOperationsLocked(); + mNumPendingFinished = 0; + } else { + mNumPendingFinished++; + } + + AuthorityInfo authority = getAuthorityLocked(op.account, op.authority, + "deleteFromPending"); + if (authority != null) { + if (DEBUG) Log.v(TAG, "removing - " + authority); + final int N = mPendingOperations.size(); + boolean morePending = false; + for (int i=0; i getPendingOperations() { + synchronized (mAuthorities) { + return new ArrayList(mPendingOperations); } - - if (numRows > 0) { - mContext.getContentResolver().notifyChange(url, null /* observer */); - } - return numRows; } - + /** - * Implements the {@link ContentProvider#update} method - * @param callerIsTheProvider true if this is being called via the - * {@link ContentProvider#update} in method rather than directly. - * @throws UnsupportedOperationException if callerIsTheProvider is true and the url isn't - * for the Settings table. + * Return the number of currently pending operations. */ - public int update(boolean callerIsTheProvider, Uri url, ContentValues initialValues, - String where, String[] whereArgs) { - switch (sURLMatcher.match(url)) { - case SETTINGS: - throw new UnsupportedOperationException("updating url " + url - + " is not allowed, use insert instead"); - default: - throw new UnsupportedOperationException("Cannot update URL: " + url); + public int getPendingOperationCount() { + synchronized (mAuthorities) { + return mPendingOperations.size(); } } - + /** - * Implements the {@link ContentProvider#getType} method + * Called when the set of account has changed, given the new array of + * active accounts. */ - public String getType(Uri url) { - int match = sURLMatcher.match(url); - switch (match) { - case SETTINGS: - return "vnd.android.cursor.dir/sync-settings"; - default: - throw new IllegalArgumentException("Unknown URL"); + public void doDatabaseCleanup(String[] accounts) { + synchronized (mAuthorities) { + if (DEBUG) Log.w(TAG, "Updating for new accounts..."); + SparseArray removing = new SparseArray(); + Iterator accIt = mAccounts.values().iterator(); + while (accIt.hasNext()) { + AccountInfo acc = accIt.next(); + if (!ArrayUtils.contains(accounts, acc.account)) { + // This account no longer exists... + if (DEBUG) Log.w(TAG, "Account removed: " + acc.account); + for (AuthorityInfo auth : acc.authorities.values()) { + removing.put(auth.ident, auth); + } + accIt.remove(); + } + } + + // Clean out all data structures. + int i = removing.size(); + if (i > 0) { + while (i > 0) { + i--; + int ident = removing.keyAt(i); + mAuthorities.remove(ident); + int j = mSyncStatus.size(); + while (j > 0) { + j--; + if (mSyncStatus.keyAt(j) == ident) { + mSyncStatus.remove(mSyncStatus.keyAt(j)); + } + } + j = mSyncHistory.size(); + while (j > 0) { + j--; + if (mSyncHistory.get(j).authorityId == ident) { + mSyncHistory.remove(j); + } + } + } + writeAccountInfoLocked(); + writeStatusLocked(); + writePendingOperationsLocked(); + writeStatisticsLocked(); + } } } - protected Uri insertIntoPending(ContentValues values) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - try { - db.beginTransaction(); - long rowId = db.insert("pending", Sync.Pending.ACCOUNT, values); - if (rowId < 0) return null; - String account = values.getAsString(Sync.Pending.ACCOUNT); - String authority = values.getAsString(Sync.Pending.AUTHORITY); - - long statsId = createStatsRowIfNecessary(account, authority); - createStatusRowIfNecessary(statsId); - - values.clear(); - values.put(Sync.Status.PENDING, 1); - int numUpdatesStatus = db.update("status", values, "stats_id=" + statsId, null); - - db.setTransactionSuccessful(); - - mContext.getContentResolver().notifyChange(Sync.Pending.CONTENT_URI, - null /* no observer initiated this change */); - if (numUpdatesStatus > 0) { - mContext.getContentResolver().notifyChange(Sync.Status.CONTENT_URI, - null /* no observer initiated this change */); + /** + * Called when the currently active sync is changing (there can only be + * one at a time). Either supply a valid ActiveSyncContext with information + * about the sync, or null to stop the currently active sync. + */ + public void setActiveSync(SyncManager.ActiveSyncContext activeSyncContext) { + synchronized (mAuthorities) { + if (activeSyncContext != null) { + if (DEBUG) Log.v(TAG, "setActiveSync: account=" + + activeSyncContext.mSyncOperation.account + + " auth=" + activeSyncContext.mSyncOperation.authority + + " src=" + activeSyncContext.mSyncOperation.syncSource + + " extras=" + activeSyncContext.mSyncOperation.extras); + if (mActiveSync != null) { + Log.w(TAG, "setActiveSync called with existing active sync!"); + } + AuthorityInfo authority = getAuthorityLocked( + activeSyncContext.mSyncOperation.account, + activeSyncContext.mSyncOperation.authority, + "setActiveSync"); + if (authority == null) { + return; + } + mActiveSync = new ActiveSyncInfo(authority.ident, + authority.account, authority.authority, + activeSyncContext.mStartTime); + } else { + if (DEBUG) Log.v(TAG, "setActiveSync: null"); + mActiveSync = null; } - return ContentUris.withAppendedId(Sync.Pending.CONTENT_URI, rowId); - } finally { - db.endTransaction(); } + + reportChange(CHANGE_ACTIVE); } - int deleteFromPending(long rowId) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - db.beginTransaction(); - try { - String account; - String authority; - Cursor c = db.query("pending", - new String[]{Sync.Pending.ACCOUNT, Sync.Pending.AUTHORITY}, - "_id=" + rowId, null, null, null, null); - try { - if (c.getCount() != 1) { - return 0; - } - c.moveToNext(); - account = c.getString(0); - authority = c.getString(1); - } finally { - c.close(); - } - db.delete("pending", "_id=" + rowId, null /* no where args */); - final String[] accountAuthorityWhereArgs = new String[]{account, authority}; - boolean isPending = 0 < DatabaseUtils.longForQuery(db, - "SELECT COUNT(*) FROM PENDING WHERE account=? AND authority=?", - accountAuthorityWhereArgs); - if (!isPending) { - long statsId = createStatsRowIfNecessary(account, authority); - db.execSQL("UPDATE status SET pending=0 WHERE stats_id=" + statsId); - } - db.setTransactionSuccessful(); - - mContext.getContentResolver().notifyChange(Sync.Pending.CONTENT_URI, - null /* no observer initiated this change */); - if (!isPending) { - mContext.getContentResolver().notifyChange(Sync.Status.CONTENT_URI, - null /* no observer initiated this change */); - } - return 1; - } finally { - db.endTransaction(); + /** + * To allow others to send active change reports, to poke clients. + */ + public void reportActiveChange() { + reportChange(CHANGE_ACTIVE); + } + + /** + * Note that sync has started for the given account and authority. + */ + public long insertStartSyncEvent(String accountName, String authorityName, + long now, int source) { + long id; + synchronized (mAuthorities) { + if (DEBUG) Log.v(TAG, "insertStartSyncEvent: account=" + accountName + + " auth=" + authorityName + " source=" + source); + AuthorityInfo authority = getAuthorityLocked(accountName, authorityName, + "insertStartSyncEvent"); + if (authority == null) { + return -1; + } + SyncHistoryItem item = new SyncHistoryItem(); + item.authorityId = authority.ident; + item.historyId = mNextHistoryId++; + if (mNextHistoryId < 0) mNextHistoryId = 0; + item.eventTime = now; + item.source = source; + item.event = EVENT_START; + mSyncHistory.add(0, item); + while (mSyncHistory.size() > MAX_HISTORY) { + mSyncHistory.remove(mSyncHistory.size()-1); + } + id = item.historyId; + if (DEBUG) Log.v(TAG, "returning historyId " + id); } + + reportChange(CHANGE_STATUS); + return id; } - int clearPending() { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - db.beginTransaction(); - try { - int numChanges = db.delete("pending", null, null /* no where args */); - if (numChanges > 0) { - db.execSQL("UPDATE status SET pending=0"); - mContext.getContentResolver().notifyChange(Sync.Pending.CONTENT_URI, - null /* no observer initiated this change */); - mContext.getContentResolver().notifyChange(Sync.Status.CONTENT_URI, - null /* no observer initiated this change */); - } - db.setTransactionSuccessful(); - return numChanges; - } finally { - db.endTransaction(); + public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage, + long downstreamActivity, long upstreamActivity) { + synchronized (mAuthorities) { + if (DEBUG) Log.v(TAG, "stopSyncEvent: historyId=" + historyId); + SyncHistoryItem item = null; + int i = mSyncHistory.size(); + while (i > 0) { + i--; + item = mSyncHistory.get(i); + if (item.historyId == historyId) { + break; + } + item = null; + } + + if (item == null) { + Log.w(TAG, "stopSyncEvent: no history for id " + historyId); + return; + } + + item.elapsedTime = elapsedTime; + item.event = EVENT_STOP; + item.mesg = resultMessage; + item.downstreamActivity = downstreamActivity; + item.upstreamActivity = upstreamActivity; + + SyncStatusInfo status = getOrCreateSyncStatusLocked(item.authorityId); + + status.numSyncs++; + status.totalElapsedTime += elapsedTime; + switch (item.source) { + case SOURCE_LOCAL: + status.numSourceLocal++; + break; + case SOURCE_POLL: + status.numSourcePoll++; + break; + case SOURCE_USER: + status.numSourceUser++; + break; + case SOURCE_SERVER: + status.numSourceServer++; + break; + } + + boolean writeStatisticsNow = false; + int day = getCurrentDayLocked(); + if (mDayStats[0] == null) { + mDayStats[0] = new DayStats(day); + } else if (day != mDayStats[0].day) { + System.arraycopy(mDayStats, 0, mDayStats, 1, mDayStats.length-1); + mDayStats[0] = new DayStats(day); + writeStatisticsNow = true; + } else if (mDayStats[0] == null) { + } + final DayStats ds = mDayStats[0]; + + final long lastSyncTime = (item.eventTime + elapsedTime); + boolean writeStatusNow = false; + if (MESG_SUCCESS.equals(resultMessage)) { + // - if successful, update the successful columns + if (status.lastSuccessTime == 0 || status.lastFailureTime != 0) { + writeStatusNow = true; + } + status.lastSuccessTime = lastSyncTime; + status.lastSuccessSource = item.source; + status.lastFailureTime = 0; + status.lastFailureSource = -1; + status.lastFailureMesg = null; + status.initialFailureTime = 0; + ds.successCount++; + ds.successTime += elapsedTime; + } else if (!MESG_CANCELED.equals(resultMessage)) { + if (status.lastFailureTime == 0) { + writeStatusNow = true; + } + status.lastFailureTime = lastSyncTime; + status.lastFailureSource = item.source; + status.lastFailureMesg = resultMessage; + if (status.initialFailureTime == 0) { + status.initialFailureTime = lastSyncTime; + } + ds.failureCount++; + ds.failureTime += elapsedTime; + } + + if (writeStatusNow) { + writeStatusLocked(); + } else if (!hasMessages(MSG_WRITE_STATUS)) { + sendMessageDelayed(obtainMessage(MSG_WRITE_STATUS), + WRITE_STATUS_DELAY); + } + if (writeStatisticsNow) { + writeStatisticsLocked(); + } else if (!hasMessages(MSG_WRITE_STATISTICS)) { + sendMessageDelayed(obtainMessage(MSG_WRITE_STATISTICS), + WRITE_STATISTICS_DELAY); + } } + + reportChange(CHANGE_STATUS); } /** - * Returns a cursor over all the pending syncs in no particular order. This cursor is not - * "live", in that if changes are made to the pending table any observers on this cursor - * will not be notified. - * @param projection Return only these columns. If null then all columns are returned. - * @return the cursor of pending syncs + * Return the currently active sync information, or null if there is no + * active sync. Note that the returned object is the real, live active + * sync object, so be careful what you do with it. */ - public Cursor getPendingSyncsCursor(String[] projection) { - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - return db.query("pending", projection, null, null, null, null, null); + public ActiveSyncInfo getActiveSync() { + synchronized (mAuthorities) { + return mActiveSync; + } } - - // @VisibleForTesting - static final long MILLIS_IN_4WEEKS = 1000L * 60 * 60 * 24 * 7 * 4; - - private boolean purgeOldHistoryEvents(long now) { - // remove events that are older than MILLIS_IN_4WEEKS - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int numDeletes = db.delete("history", "eventTime<" + (now - MILLIS_IN_4WEEKS), null); - if (Log.isLoggable(TAG, Log.VERBOSE)) { - if (numDeletes > 0) { - Log.v(TAG, "deleted " + numDeletes + " old event(s) from the sync history"); + + /** + * Return an array of the current sync status for all authorities. Note + * that the objects inside the array are the real, live status objects, + * so be careful what you do with them. + */ + public ArrayList getSyncStatus() { + synchronized (mAuthorities) { + final int N = mSyncStatus.size(); + ArrayList ops = new ArrayList(N); + for (int i=0; i 0; } - - public long insertStartSyncEvent(String account, String authority, long now, int source) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - long statsId = createStatsRowIfNecessary(account, authority); - - purgeOldHistoryEvents(now); - ContentValues values = new ContentValues(); - values.put(Sync.History.STATS_ID, statsId); - values.put(Sync.History.EVENT_TIME, now); - values.put(Sync.History.SOURCE, source); - values.put(Sync.History.EVENT, Sync.History.EVENT_START); - long rowId = db.insert("history", null, values); - mContext.getContentResolver().notifyChange(Sync.History.CONTENT_URI, null /* observer */); - mContext.getContentResolver().notifyChange(Sync.Status.CONTENT_URI, null /* observer */); - return rowId; + + /** + * Returns the status that matches the authority. If there are multiples accounts for + * the authority, the one with the latest "lastSuccessTime" status is returned. + * @param authority the authority whose row should be selected + * @return the SyncStatusInfo for the authority, or null if none exists + */ + public SyncStatusInfo getStatusByAuthority(String authority) { + synchronized (mAuthorities) { + SyncStatusInfo best = null; + final int N = mSyncStatus.size(); + for (int i=0; i cur.lastSuccessTime) { + best = cur; + } + } + } + return best; + } } - - public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage, - long downstreamActivity, long upstreamActivity) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - db.beginTransaction(); - try { - ContentValues values = new ContentValues(); - values.put(Sync.History.ELAPSED_TIME, elapsedTime); - values.put(Sync.History.EVENT, Sync.History.EVENT_STOP); - values.put(Sync.History.MESG, resultMessage); - values.put(Sync.History.DOWNSTREAM_ACTIVITY, downstreamActivity); - values.put(Sync.History.UPSTREAM_ACTIVITY, upstreamActivity); - - int count = db.update("history", values, "_id=?", - new String[]{Long.toString(historyId)}); - // We think that count should always be 1 but don't want to change this until after - // launch. - if (count > 0) { - int source = (int) DatabaseUtils.longForQuery(db, - "SELECT source FROM history WHERE _id=" + historyId, null); - long eventTime = DatabaseUtils.longForQuery(db, - "SELECT eventTime FROM history WHERE _id=" + historyId, null); - long statsId = DatabaseUtils.longForQuery(db, - "SELECT stats_id FROM history WHERE _id=" + historyId, null); - - createStatusRowIfNecessary(statsId); - - // update the status table to reflect this sync - StringBuilder sb = new StringBuilder(); - ArrayList bindArgs = new ArrayList(); - sb.append("UPDATE status SET"); - sb.append(" numSyncs=numSyncs+1"); - sb.append(", totalElapsedTime=totalElapsedTime+" + elapsedTime); - switch (source) { - case Sync.History.SOURCE_LOCAL: - sb.append(", numSourceLocal=numSourceLocal+1"); - break; - case Sync.History.SOURCE_POLL: - sb.append(", numSourcePoll=numSourcePoll+1"); - break; - case Sync.History.SOURCE_USER: - sb.append(", numSourceUser=numSourceUser+1"); - break; - case Sync.History.SOURCE_SERVER: - sb.append(", numSourceServer=numSourceServer+1"); - break; + + /** + * Return true if the pending status is true of any matching authorities. + */ + public boolean isAuthorityPending(String account, String authority) { + synchronized (mAuthorities) { + final int N = mSyncStatus.size(); + for (int i=0; i getSyncHistory() { + synchronized (mAuthorities) { + final int N = mSyncHistory.size(); + ArrayList items = new ArrayList(N); + for (int i=0; i 0) { + i--; + SyncStatusInfo stats = mSyncStatus.valueAt(i); + AuthorityInfo authority = mAuthorities.get(stats.authorityId); + if (authority != null && authority.enabled) { + if (oldest == 0 || stats.initialFailureTime < oldest) { + oldest = stats.initialFailureTime; + } + } + } + + return oldest; + } + } + + private int getCurrentDayLocked() { + mCal.setTimeInMillis(System.currentTimeMillis()); + final int dayOfYear = mCal.get(Calendar.DAY_OF_YEAR); + if (mYear != mCal.get(Calendar.YEAR)) { + mYear = mCal.get(Calendar.YEAR); + mCal.clear(); + mCal.set(Calendar.YEAR, mYear); + mYearInDays = (int)(mCal.getTimeInMillis()/86400000); + } + return dayOfYear + mYearInDays; + } + + /** + * Retrieve an authority, returning null if one does not exist. + * + * @param accountName The name of the account for the authority. + * @param authorityName The name of the authority itself. + * @param tag If non-null, this will be used in a log message if the + * requested authority does not exist. + */ + private AuthorityInfo getAuthorityLocked(String accountName, String authorityName, + String tag) { + AccountInfo account = mAccounts.get(accountName); + if (account == null) { + if (tag != null) { + Log.w(TAG, tag + ": unknown account " + accountName); + } + return null; + } + AuthorityInfo authority = account.authorities.get(authorityName); + if (authority == null) { + if (tag != null) { + Log.w(TAG, tag + ": unknown authority " + authorityName); + } + return null; + } + + return authority; + } + + private AuthorityInfo getOrCreateAuthorityLocked(String accountName, + String authorityName, int ident, boolean doWrite) { + AccountInfo account = mAccounts.get(accountName); + if (account == null) { + account = new AccountInfo(accountName); + mAccounts.put(accountName, account); + } + AuthorityInfo authority = account.authorities.get(authorityName); + if (authority == null) { + if (ident < 0) { + // Look for a new identifier for this authority. + final int N = mAuthorities.size(); + ident = 0; + for (int i=0; i ident) { + break; + } + ident++; + } + } + authority = new AuthorityInfo(accountName, authorityName, ident); + account.authorities.put(authorityName, authority); + mAuthorities.put(ident, authority); + if (doWrite) { + writeAccountInfoLocked(); + } + } + + return authority; + } + + private SyncStatusInfo getOrCreateSyncStatusLocked(int authorityId) { + SyncStatusInfo status = mSyncStatus.get(authorityId); + if (status == null) { + status = new SyncStatusInfo(authorityId); + mSyncStatus.put(authorityId, status); + } + return status; + } + + public void writeAllState() { + synchronized (mAuthorities) { + // Account info is always written so no need to do it here. + + if (mNumPendingFinished > 0) { + // Only write these if they are out of date. + writePendingOperationsLocked(); + } + + // Just always write these... they are likely out of date. + writeStatusLocked(); + writeStatisticsLocked(); + } + } + + /** + * Read all account information back in to the initial engine state. + */ + private void readAccountInfoLocked() { + FileInputStream fis = null; + try { + fis = mAccountInfoFile.openRead(); + if (DEBUG_FILE) Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile()); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(fis, null); + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.START_TAG) { + eventType = parser.next(); + } + String tagName = parser.getName(); + if ("accounts".equals(tagName)) { + String listen = parser.getAttributeValue( + null, "listen-for-tickles"); + mListenForTickles = listen == null + || Boolean.parseBoolean(listen); + eventType = parser.next(); + do { + if (eventType == XmlPullParser.START_TAG + && parser.getDepth() == 2) { + tagName = parser.getName(); + if ("authority".equals(tagName)) { + int id = -1; + try { + id = Integer.parseInt(parser.getAttributeValue( + null, "id")); + } catch (NumberFormatException e) { + } catch (NullPointerException e) { + } + if (id >= 0) { + String accountName = parser.getAttributeValue( + null, "account"); + String authorityName = parser.getAttributeValue( + null, "authority"); + String enabled = parser.getAttributeValue( + null, "enabled"); + AuthorityInfo authority = mAuthorities.get(id); + if (DEBUG_FILE) Log.v(TAG, "Adding authority: account=" + + accountName + " auth=" + authorityName + + " enabled=" + enabled); + if (authority == null) { + if (DEBUG_FILE) Log.v(TAG, "Creating entry"); + authority = getOrCreateAuthorityLocked( + accountName, authorityName, id, false); + } + if (authority != null) { + authority.enabled = enabled == null + || Boolean.parseBoolean(enabled); + } else { + Log.w(TAG, "Failure adding authority: account=" + + accountName + " auth=" + authorityName + + " enabled=" + enabled); + } + } + } + } + eventType = parser.next(); + } while (eventType != XmlPullParser.END_DOCUMENT); + } + } catch (XmlPullParserException e) { + Log.w(TAG, "Error reading accounts", e); + } catch (java.io.IOException e) { + if (fis == null) Log.i(TAG, "No initial accounts"); + else Log.w(TAG, "Error reading accounts", e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (java.io.IOException e1) { + } + } + } + } + + /** + * Write all account information to the account file. + */ + private void writeAccountInfoLocked() { + if (DEBUG_FILE) Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile()); + FileOutputStream fos = null; + + try { + fos = mAccountInfoFile.startWrite(); + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, "utf-8"); + out.startDocument(null, true); + out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + + out.startTag(null, "accounts"); + if (!mListenForTickles) { + out.attribute(null, "listen-for-tickles", "false"); + } + + final int N = mAuthorities.size(); + for (int i=0; i map = new HashMap(); + map.put("_id", "status._id as _id"); + map.put("account", "stats.account as account"); + map.put("authority", "stats.authority as authority"); + map.put("totalElapsedTime", "totalElapsedTime"); + map.put("numSyncs", "numSyncs"); + map.put("numSourceLocal", "numSourceLocal"); + map.put("numSourcePoll", "numSourcePoll"); + map.put("numSourceServer", "numSourceServer"); + map.put("numSourceUser", "numSourceUser"); + map.put("lastSuccessSource", "lastSuccessSource"); + map.put("lastSuccessTime", "lastSuccessTime"); + map.put("lastFailureSource", "lastFailureSource"); + map.put("lastFailureTime", "lastFailureTime"); + map.put("lastFailureMesg", "lastFailureMesg"); + map.put("pending", "pending"); + qb.setProjectionMap(map); + qb.appendWhere("stats._id = status.stats_id"); + Cursor c = qb.query(db, null, null, null, null, null, null); while (c.moveToNext()) { - // these settings default to true, so if they are null treat them as enabled - final String providerEnabledString = c.getString(1); - if (providerEnabledString != null && !Boolean.parseBoolean(providerEnabledString)) { - continue; + String accountName = c.getString(c.getColumnIndex("account")); + String authorityName = c.getString(c.getColumnIndex("authority")); + AuthorityInfo authority = this.getOrCreateAuthorityLocked( + accountName, authorityName, -1, false); + if (authority != null) { + int i = mSyncStatus.size(); + boolean found = false; + SyncStatusInfo st = null; + while (i > 0) { + i--; + st = mSyncStatus.get(i); + if (st.authorityId == authority.ident) { + found = true; + break; + } + } + if (!found) { + st = new SyncStatusInfo(authority.ident); + mSyncStatus.put(authority.ident, st); + } + st.totalElapsedTime = getLongColumn(c, "totalElapsedTime"); + st.numSyncs = getIntColumn(c, "numSyncs"); + st.numSourceLocal = getIntColumn(c, "numSourceLocal"); + st.numSourcePoll = getIntColumn(c, "numSourcePoll"); + st.numSourceServer = getIntColumn(c, "numSourceServer"); + st.numSourceUser = getIntColumn(c, "numSourceUser"); + st.lastSuccessSource = getIntColumn(c, "lastSuccessSource"); + st.lastSuccessTime = getLongColumn(c, "lastSuccessTime"); + st.lastFailureSource = getIntColumn(c, "lastFailureSource"); + st.lastFailureTime = getLongColumn(c, "lastFailureTime"); + st.lastFailureMesg = c.getString(c.getColumnIndex("lastFailureMesg")); + st.pending = getIntColumn(c, "pending") != 0; } - final String allEnabledString = c.getString(2); - if (allEnabledString != null && !Boolean.parseBoolean(allEnabledString)) { - continue; + } + + c.close(); + + // Retrieve the settings. + qb = new SQLiteQueryBuilder(); + qb.setTables("settings"); + c = qb.query(db, null, null, null, null, null, null); + while (c.moveToNext()) { + String name = c.getString(c.getColumnIndex("name")); + String value = c.getString(c.getColumnIndex("value")); + if (name == null) continue; + if (name.equals("listen_for_tickles")) { + setListenForNetworkTickles(value == null + || Boolean.parseBoolean(value)); + } else if (name.startsWith("sync_provider_")) { + String provider = name.substring("sync_provider_".length(), + name.length()); + setSyncProviderAutomatically(null, provider, + value == null || Boolean.parseBoolean(value)); } - return c.getLong(0); } - } finally { + c.close(); + + db.close(); + + writeAccountInfoLocked(); + writeStatusLocked(); + (new File(path)).delete(); } - return 0; } - - private void createStatusRowIfNecessary(long statsId) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - boolean statusExists = 0 != DatabaseUtils.longForQuery(db, - "SELECT count(*) FROM status WHERE stats_id=" + statsId, null); - if (!statusExists) { - ContentValues values = new ContentValues(); - values.put("stats_id", statsId); - db.insert("status", null, values); + + public static final int STATUS_FILE_END = 0; + public static final int STATUS_FILE_ITEM = 100; + + /** + * Read all sync status back in to the initial engine state. + */ + private void readStatusLocked() { + if (DEBUG_FILE) Log.v(TAG, "Reading " + mStatusFile.getBaseFile()); + try { + byte[] data = mStatusFile.readFully(); + Parcel in = Parcel.obtain(); + in.unmarshall(data, 0, data.length); + in.setDataPosition(0); + int token; + while ((token=in.readInt()) != STATUS_FILE_END) { + if (token == STATUS_FILE_ITEM) { + SyncStatusInfo status = new SyncStatusInfo(in); + if (mAuthorities.indexOfKey(status.authorityId) >= 0) { + status.pending = false; + if (DEBUG_FILE) Log.v(TAG, "Adding status for id " + + status.authorityId); + mSyncStatus.put(status.authorityId, status); + } + } else { + // Ooops. + Log.w(TAG, "Unknown status token: " + token); + break; + } + } + } catch (java.io.IOException e) { + Log.i(TAG, "No initial status"); } } - - private long createStatsRowIfNecessary(String account, String authority) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - StringBuilder where = new StringBuilder(); - where.append(Sync.Stats.ACCOUNT + "= ?"); - where.append(" and " + Sync.Stats.AUTHORITY + "= ?"); - Cursor cursor = query(Sync.Stats.CONTENT_URI, - Sync.Stats.SYNC_STATS_PROJECTION, - where.toString(), new String[] { account, authority }, - null /* order */); + + /** + * Write all sync status to the sync status file. + */ + private void writeStatusLocked() { + if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatusFile.getBaseFile()); + + // The file is being written, so we don't need to have a scheduled + // write until the next change. + removeMessages(MSG_WRITE_STATUS); + + FileOutputStream fos = null; try { - long id; - if (cursor.moveToFirst()) { - id = cursor.getLong(cursor.getColumnIndexOrThrow(Sync.Stats._ID)); - } else { - ContentValues values = new ContentValues(); - values.put(Sync.Stats.ACCOUNT, account); - values.put(Sync.Stats.AUTHORITY, authority); - id = db.insert("stats", null, values); + fos = mStatusFile.startWrite(); + Parcel out = Parcel.obtain(); + final int N = mSyncStatus.size(); + for (int i=0; i pathSegments = uri.getPathSegments(); + final int li = pathSegments.size(); UriMatcher node = this; @@ -209,7 +211,7 @@ public class UriMatcher } for (int i=-1; i list = node.mChildren; if (list == null) { break; diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 8d727ed9d0b4361d73ba16562cb8d4cd56f4b9bc..88ac04c24e6df912e60ea73655c3ef8aa66eeaf2 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -113,19 +113,31 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6; - /** - * Value for {@link #flags}: default value for the corresponding ActivityInfo flag. - * {@hide} + * Value for {@link #flags}: this is set if this application has been + * install as an update to a built-in system application. */ public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7; + + /** + * Value for {@link #flags}: this is set of the application has set + * its android:targetSdkVersion to something >= the current SDK version. + */ + public static final int FLAG_TARGETS_SDK = 1<<8; + + /** + * Value for {@link #flags}: this is set of the application has set + * its android:targetSdkVersion to something >= the current SDK version. + */ + public static final int FLAG_TEST_ONLY = 1<<9; /** * Flags associated with the application. Any combination of * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE}, * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and * {@link #FLAG_ALLOW_TASK_REPARENTING} - * {@link #FLAG_ALLOW_CLEAR_USER_DATA}. + * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP}, + * {@link #FLAG_TARGETS_SDK}. */ public int flags = 0; @@ -161,6 +173,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public int uid; + + /** + * The list of densities in DPI that application supprots. This + * field is only set if the {@link PackageManager#GET_SUPPORTS_DENSITIES} flag was + * used when retrieving the structure. + */ + public int[] supportsDensities; + /** * When false, indicates that all components within this application are * considered disabled, regardless of their individually set enabled status. @@ -181,8 +201,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles); pw.println(prefix + "dataDir=" + dataDir); pw.println(prefix + "enabled=" + enabled); - pw.println(prefix+"manageSpaceActivityName="+manageSpaceActivityName); - pw.println(prefix+"description=0x"+Integer.toHexString(descriptionRes)); + pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName); + pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes)); + pw.println(prefix + "supportsDensities=" + supportsDensities); super.dumpBack(pw, prefix); } @@ -228,6 +249,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { enabled = orig.enabled; manageSpaceActivityName = orig.manageSpaceActivityName; descriptionRes = orig.descriptionRes; + supportsDensities = orig.supportsDensities; } @@ -257,6 +279,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(enabled ? 1 : 0); dest.writeString(manageSpaceActivityName); dest.writeInt(descriptionRes); + dest.writeIntArray(supportsDensities); } public static final Parcelable.Creator CREATOR @@ -285,8 +308,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { enabled = source.readInt() != 0; manageSpaceActivityName = source.readString(); descriptionRes = source.readInt(); + supportsDensities = source.createIntArray(); } - + /** * Retrieve the textual description of the application. This * will call back on the given PackageManager to load the description from diff --git a/core/java/android/content/pm/IPackageInstallObserver.aidl b/core/java/android/content/pm/IPackageInstallObserver.aidl index e83bbc67d117a2ce6bf17c8fb2198d177f3ac2f5..61333653731787c967e64b8beeecd6fff2edbd8c 100644 --- a/core/java/android/content/pm/IPackageInstallObserver.aidl +++ b/core/java/android/content/pm/IPackageInstallObserver.aidl @@ -19,7 +19,7 @@ package android.content.pm; /** * API for installation callbacks from the Package Manager. - * + * @hide */ oneway interface IPackageInstallObserver { void packageInstalled(in String packageName, int returnCode); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index d3f6f3c564c89e68ef0d194c62e7f479565540f6..c199619c57a92ba6168c9e6d223b411fc008e44a 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -139,8 +139,11 @@ interface IPackageManager { * @param observer a callback to use to notify when the package installation in finished. * @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE}, * {@link #REPLACE_EXISITING_PACKAGE} + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. */ - void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags); + void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags, + in String installerPackageName); /** * Delete a package. @@ -151,6 +154,8 @@ interface IPackageManager { */ void deletePackage(in String packageName, IPackageDeleteObserver observer, int flags); + String getInstallerPackageName(in String packageName); + void addPackageToPreferred(String packageName); void removePackageFromPreferred(String packageName); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3e9473472dcb399632c6040cd4724a5b262f9015..3a192f7eb7493168da4d0e9ce42446032dac89df 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -165,6 +165,20 @@ public abstract class PackageManager { */ public static final int GET_CONFIGURATIONS = 0x00004000; + /** + * {@link ApplicationInfo} flag: return the + * {@link ApplicationInfo#supportsDensities} that the package supports. + */ + public static final int GET_SUPPORTS_DENSITIES = 0x00008000; + + /** + * Resolution and querying flag: if set, only filters that support the + * {@link android.content.Intent#CATEGORY_DEFAULT} will be considered for + * matching. This is a synonym for including the CATEGORY_DEFAULT in your + * supplied Intent. + */ + public static final int MATCH_DEFAULT_ONLY = 0x00010000; + /** * Permission check result: this is returned by {@link #checkPermission} * if the permission has been granted to the given package. @@ -213,14 +227,6 @@ public abstract class PackageManager { */ public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; - /** - * Resolution and querying flag: if set, only filters that support the - * {@link android.content.Intent#CATEGORY_DEFAULT} will be considered for - * matching. This is a synonym for including the CATEGORY_DEFAULT in your - * supplied Intent. - */ - public static final int MATCH_DEFAULT_ONLY = 0x00010000; - public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; @@ -229,14 +235,24 @@ public abstract class PackageManager { * Flag parameter for {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} to * indicate that this package should be installed as forward locked, i.e. only the app itself * should have access to it's code and non-resource assets. + * @hide */ - public static final int FORWARD_LOCK_PACKAGE = 0x00000001; + public static final int INSTALL_FORWARD_LOCK = 0x00000001; /** * Flag parameter for {@link #installPackage} to indicate that you want to replace an already - * installed package, if one exists + * installed package, if one exists. + * @hide + */ + public static final int INSTALL_REPLACE_EXISTING = 0x00000002; + + /** + * Flag parameter for {@link #installPackage} to indicate that you want to + * allow test packages (those that have set android:testOnly in their + * manifest) to be installed. + * @hide */ - public static final int REPLACE_EXISTING_PACKAGE = 0x00000002; + public static final int INSTALL_ALLOW_TEST = 0x00000004; /** * Flag parameter for @@ -249,6 +265,7 @@ public abstract class PackageManager { /** * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on success. + * @hide */ public static final int INSTALL_SUCCEEDED = 1; @@ -256,6 +273,7 @@ public abstract class PackageManager { * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package is * already installed. + * @hide */ public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; @@ -263,6 +281,7 @@ public abstract class PackageManager { * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package archive * file is invalid. + * @hide */ public static final int INSTALL_FAILED_INVALID_APK = -2; @@ -270,13 +289,15 @@ public abstract class PackageManager { * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the URI passed in * is invalid. + * @hide */ public static final int INSTALL_FAILED_INVALID_URI = -3; /** * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package manager - * service found that the device didn't have enough storage space to install the app + * service found that the device didn't have enough storage space to install the app. + * @hide */ public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4; @@ -284,6 +305,7 @@ public abstract class PackageManager { * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if a * package is already installed with the same name. + * @hide */ public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5; @@ -291,6 +313,7 @@ public abstract class PackageManager { * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * the requested shared user does not exist. + * @hide */ public static final int INSTALL_FAILED_NO_SHARED_USER = -6; @@ -299,6 +322,7 @@ public abstract class PackageManager { * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * a previously installed package of the same name has a different signature * than the new package (and the old package's data was not removed). + * @hide */ public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7; @@ -307,6 +331,7 @@ public abstract class PackageManager { * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * the new package is requested a shared user which is already installed on the * device and does not have matching signature. + * @hide */ public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8; @@ -314,6 +339,7 @@ public abstract class PackageManager { * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * the new package uses a shared library that is not available. + * @hide */ public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9; @@ -321,6 +347,7 @@ public abstract class PackageManager { * Installation return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * the new package uses a shared library that is not available. + * @hide */ public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10; @@ -329,6 +356,7 @@ public abstract class PackageManager { * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * the new package failed while optimizing and validating its dex files, * either because there was not enough storage or the validation failed. + * @hide */ public static final int INSTALL_FAILED_DEXOPT = -11; @@ -337,6 +365,7 @@ public abstract class PackageManager { * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * the new package failed because the current SDK version is older than * that required by the package. + * @hide */ public static final int INSTALL_FAILED_OLDER_SDK = -12; @@ -345,14 +374,35 @@ public abstract class PackageManager { * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if * the new package failed because it contains a content provider with the * same authority as a provider already installed in the system. + * @hide */ public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; + /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the new package failed because the current SDK version is newer than + * that required by the package. + * @hide + */ + public static final int INSTALL_FAILED_NEWER_SDK = -14; + + /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the new package failed because it has specified that it is a test-only + * package and the caller has not supplied the {@link #INSTALL_ALLOW_TEST} + * flag. + * @hide + */ + public static final int INSTALL_FAILED_TEST_ONLY = -15; + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser was given a path that is not a file, or does not end with the expected * '.apk' extension. + * @hide */ public static final int INSTALL_PARSE_FAILED_NOT_APK = -100; @@ -360,6 +410,7 @@ public abstract class PackageManager { * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser was unable to retrieve the AndroidManifest.xml file. + * @hide */ public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101; @@ -367,6 +418,7 @@ public abstract class PackageManager { * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser encountered an unexpected exception. + * @hide */ public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; @@ -374,6 +426,7 @@ public abstract class PackageManager { * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser did not find any certificates in the .apk. + * @hide */ public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; @@ -381,6 +434,7 @@ public abstract class PackageManager { * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser found inconsistent certificates on the files in the .apk. + * @hide */ public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104; @@ -389,6 +443,7 @@ public abstract class PackageManager { * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser encountered a CertificateEncodingException in one of the * files in the .apk. + * @hide */ public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105; @@ -396,6 +451,7 @@ public abstract class PackageManager { * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser encountered a bad or missing package name in the manifest. + * @hide */ public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106; @@ -403,6 +459,7 @@ public abstract class PackageManager { * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser encountered a bad shared user id name in the manifest. + * @hide */ public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107; @@ -410,6 +467,7 @@ public abstract class PackageManager { * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser encountered some structural problem in the manifest. + * @hide */ public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108; @@ -418,6 +476,7 @@ public abstract class PackageManager { * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser did not find any actionable tags (instrumentation or application) * in the manifest. + * @hide */ public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109; @@ -1324,6 +1383,8 @@ public abstract class PackageManager { } /** + * @hide + * * Install a package. Since this may take a little while, the result will * be posted back to the given observer. An installation will fail if the calling context * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the @@ -1335,13 +1396,14 @@ public abstract class PackageManager { * @param observer An observer callback to get notified when the package installation is * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be * called when that happens. observer may be null to indicate that no callback is desired. - * @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE}, - * {@link #REPLACE_EXISTING_PACKAGE} - * - * @see #installPackage(android.net.Uri) + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. */ public abstract void installPackage( - Uri packageURI, IPackageInstallObserver observer, int flags); + Uri packageURI, IPackageInstallObserver observer, int flags, + String installerPackageName); /** * Attempts to delete a package. Since this may take a little while, the result will @@ -1360,6 +1422,17 @@ public abstract class PackageManager { */ public abstract void deletePackage( String packageName, IPackageDeleteObserver observer, int flags); + + /** + * Retrieve the package name of the application that installed a package. This identifies + * which market the package came from. + * + * @param packageName The name of the package to query + * + * @hide + */ + public abstract String getInstallerPackageName(String packageName); + /** * Attempts to clear the user data directory of an application. * Since this may take a little while, the result will @@ -1464,17 +1537,6 @@ public abstract class PackageManager { public abstract void getPackageSizeInfo(String packageName, IPackageStatsObserver observer); - /** - * Install a package. - * - * @param packageURI The location of the package file to install - * - * @see #installPackage(android.net.Uri, IPackageInstallObserver, int) - */ - public void installPackage(Uri packageURI) { - installPackage(packageURI, null, 0); - } - /** * Add a new package to the list of preferred packages. This new package * will be added to the front of the list (removed from its current location diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 2dcb4830bf48474301b78e3ce20ac10a38ea86e8..88907c180117f15546c410151cabcbf2eb927890 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -45,6 +45,7 @@ import java.security.cert.CertificateEncodingException; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; +import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -58,12 +59,55 @@ public class PackageParser { private String mArchiveSourcePath; private String[] mSeparateProcesses; private int mSdkVersion; + private String mSdkCodename; private int mParseError = PackageManager.INSTALL_SUCCEEDED; private static final Object mSync = new Object(); private static WeakReference mReadBuffer; + static class ParsePackageItemArgs { + final Package owner; + final String[] outError; + final int nameRes; + final int labelRes; + final int iconRes; + + String tag; + TypedArray sa; + + ParsePackageItemArgs(Package _owner, String[] _outError, + int _nameRes, int _labelRes, int _iconRes) { + owner = _owner; + outError = _outError; + nameRes = _nameRes; + labelRes = _labelRes; + iconRes = _iconRes; + } + } + + static class ParseComponentArgs extends ParsePackageItemArgs { + final String[] sepProcesses; + final int processRes; + final int enabledRes; + int flags; + + ParseComponentArgs(Package _owner, String[] _outError, + int _nameRes, int _labelRes, int _iconRes, + String[] _sepProcesses, int _processRes,int _enabledRes) { + super(_owner, _outError, _nameRes, _labelRes, _iconRes); + sepProcesses = _sepProcesses; + processRes = _processRes; + enabledRes = _enabledRes; + } + } + + private ParsePackageItemArgs mParseInstrumentationArgs; + private ParseComponentArgs mParseActivityArgs; + private ParseComponentArgs mParseActivityAliasArgs; + private ParseComponentArgs mParseServiceArgs; + private ParseComponentArgs mParseProviderArgs; + /** If set to true, we will only allow package files that exactly match * the DTD. Otherwise, we try to get as much from the package as we * can without failing. This should normally be set to false, to @@ -80,8 +124,9 @@ public class PackageParser { mSeparateProcesses = procs; } - public void setSdkVersion(int sdkVersion) { + public void setSdkVersion(int sdkVersion, String codename) { mSdkVersion = sdkVersion; + mSdkCodename = codename; } private static final boolean isPackageFilename(String name) { @@ -557,6 +602,11 @@ public class PackageParser { throws XmlPullParserException, IOException { AttributeSet attrs = parser; + mParseInstrumentationArgs = null; + mParseActivityArgs = null; + mParseServiceArgs = null; + mParseProviderArgs = null; + String pkgName = parsePackageName(parser, attrs, flags, outError); if (pkgName == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; @@ -565,9 +615,9 @@ public class PackageParser { int type; final Package pkg = new Package(pkgName); - pkg.mSystem = (flags&PARSE_IS_SYSTEM) != 0; boolean foundApp = false; - + boolean targetsSdk = false; + TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifest); pkg.mVersionCode = sa.getInteger( @@ -593,8 +643,6 @@ public class PackageParser { } sa.recycle(); - final int innerDepth = parser.getDepth(); - int outerDepth = parser.getDepth(); while ((type=parser.next()) != parser.END_DOCUMENT && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { @@ -675,19 +723,74 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("uses-sdk")) { + } else if (tagName.equals("uses-sdk")) { if (mSdkVersion > 0) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestUsesSdk); - int vers = sa.getInt( - com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion, 0); + int minVers = 0; + String minCode = null; + int targetVers = 0; + String targetCode = null; + + TypedValue val = sa.peekValue( + com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + targetCode = minCode = val.string.toString(); + } else { + // If it's not a string, it's an integer. + minVers = val.data; + } + } + + val = sa.peekValue( + com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + targetCode = minCode = val.string.toString(); + } else { + // If it's not a string, it's an integer. + targetVers = val.data; + } + } + + int maxVers = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesSdk_maxSdkVersion, + mSdkVersion); sa.recycle(); - if (vers > mSdkVersion) { - outError[0] = "Requires newer sdk version #" + vers - + " (current version is #" + mSdkVersion + ")"; + if (targetCode != null) { + if (!targetCode.equals(mSdkCodename)) { + if (mSdkCodename != null) { + outError[0] = "Requires development platform " + targetCode + + " (current platform is " + mSdkCodename + ")"; + } else { + outError[0] = "Requires development platform " + targetCode + + " but this is a release platform."; + } + mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; + return null; + } + // If the code matches, it definitely targets this SDK. + targetsSdk = true; + } else if (targetVers >= mSdkVersion) { + // If they have explicitly targeted our current version + // or something after it, then note this. + targetsSdk = true; + } + + if (minVers > mSdkVersion) { + outError[0] = "Requires newer sdk version #" + minVers + + " (current version is #" + mSdkVersion + ")"; + mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; + return null; + } + + if (maxVers < mSdkVersion) { + outError[0] = "Requires older sdk version #" + maxVers + + " (current version is #" + mSdkVersion + ")"; mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } @@ -721,11 +824,23 @@ public class PackageParser { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; } + if (targetsSdk) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_TARGETS_SDK; + } + if (pkg.usesLibraries.size() > 0) { pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()]; pkg.usesLibraries.toArray(pkg.usesLibraryFiles); } + int size = pkg.supportsDensityList.size(); + if (size > 0) { + int densities[] = pkg.supportsDensities = new int[size]; + List densityList = pkg.supportsDensityList; + for (int i = 0; i < size; i++) { + densities[i] = densityList.get(i); + } + } return pkg; } @@ -950,20 +1065,24 @@ public class PackageParser { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestInstrumentation); - Instrumentation a = new Instrumentation(owner); - - if (!parsePackageItemInfo(owner, a.info, outError, "", sa, - com.android.internal.R.styleable.AndroidManifestInstrumentation_name, - com.android.internal.R.styleable.AndroidManifestInstrumentation_label, - com.android.internal.R.styleable.AndroidManifestInstrumentation_icon)) { + if (mParseInstrumentationArgs == null) { + mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, + com.android.internal.R.styleable.AndroidManifestInstrumentation_name, + com.android.internal.R.styleable.AndroidManifestInstrumentation_label, + com.android.internal.R.styleable.AndroidManifestInstrumentation_icon); + mParseInstrumentationArgs.tag = ""; + } + + mParseInstrumentationArgs.sa = sa; + + Instrumentation a = new Instrumentation(mParseInstrumentationArgs, + new InstrumentationInfo()); + if (outError[0] != null) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } - a.component = new ComponentName(owner.applicationInfo.packageName, - a.info.name); - String str; str = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage); @@ -1068,6 +1187,12 @@ public class PackageParser { ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; } + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_testOnly, + false)) { + ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; + } + String str; str = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestApplication_permission); @@ -1140,7 +1265,7 @@ public class PackageParser { owner.providers.add(p); } else if (tagName.equals("activity-alias")) { - Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError, false); + Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError); if (a == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; @@ -1173,6 +1298,21 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("supports-density")) { + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestSupportsDensity); + + int density = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsDensity_density, -1); + + sa.recycle(); + + if (density != -1 && !owner.supportsDensityList.contains(density)) { + owner.supportsDensityList.add(density); + } + + XmlUtils.skipCurrentTag(parser); + } else { if (!RIGID_PARSER) { Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); @@ -1239,22 +1379,29 @@ public class PackageParser { return outError[0] == null; } - + private Activity parseActivity(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, boolean receiver) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestActivity); - Activity a = new Activity(owner); - - if (!parseComponentInfo(owner, flags, a.info, outError, - receiver ? "" : "", sa, - com.android.internal.R.styleable.AndroidManifestActivity_name, - com.android.internal.R.styleable.AndroidManifestActivity_label, - com.android.internal.R.styleable.AndroidManifestActivity_icon, - com.android.internal.R.styleable.AndroidManifestActivity_process, - com.android.internal.R.styleable.AndroidManifestActivity_enabled)) { + if (mParseActivityArgs == null) { + mParseActivityArgs = new ParseComponentArgs(owner, outError, + com.android.internal.R.styleable.AndroidManifestActivity_name, + com.android.internal.R.styleable.AndroidManifestActivity_label, + com.android.internal.R.styleable.AndroidManifestActivity_icon, + mSeparateProcesses, + com.android.internal.R.styleable.AndroidManifestActivity_process, + com.android.internal.R.styleable.AndroidManifestActivity_enabled); + } + + mParseActivityArgs.tag = receiver ? "" : ""; + mParseActivityArgs.sa = sa; + mParseActivityArgs.flags = flags; + + Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); + if (outError[0] != null) { sa.recycle(); return null; } @@ -1266,9 +1413,6 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivity_exported, false); } - a.component = new ComponentName(owner.applicationInfo.packageName, - a.info.name); - a.info.theme = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestActivity_theme, 0); @@ -1412,8 +1556,8 @@ public class PackageParser { } private Activity parseActivityAlias(Package owner, Resources res, - XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, - boolean receiver) throws XmlPullParserException, IOException { + XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) + throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestActivityAlias); @@ -1432,7 +1576,20 @@ public class PackageParser { return null; } - Activity a = new Activity(owner); + if (mParseActivityAliasArgs == null) { + mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, + com.android.internal.R.styleable.AndroidManifestActivityAlias_name, + com.android.internal.R.styleable.AndroidManifestActivityAlias_label, + com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, + mSeparateProcesses, + 0, + com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); + mParseActivityAliasArgs.tag = ""; + } + + mParseActivityAliasArgs.sa = sa; + mParseActivityAliasArgs.flags = flags; + Activity target = null; final int NA = owner.activities.size(); @@ -1451,26 +1608,21 @@ public class PackageParser { return null; } - a.info.targetActivity = targetActivity; - - a.info.configChanges = target.info.configChanges; - a.info.flags = target.info.flags; - a.info.icon = target.info.icon; - a.info.labelRes = target.info.labelRes; - a.info.launchMode = target.info.launchMode; - a.info.nonLocalizedLabel = target.info.nonLocalizedLabel; - a.info.processName = target.info.processName; - a.info.screenOrientation = target.info.screenOrientation; - a.info.taskAffinity = target.info.taskAffinity; - a.info.theme = target.info.theme; - - if (!parseComponentInfo(owner, flags, a.info, outError, - receiver ? "" : "", sa, - com.android.internal.R.styleable.AndroidManifestActivityAlias_name, - com.android.internal.R.styleable.AndroidManifestActivityAlias_label, - com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, - 0, - com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled)) { + ActivityInfo info = new ActivityInfo(); + info.targetActivity = targetActivity; + info.configChanges = target.info.configChanges; + info.flags = target.info.flags; + info.icon = target.info.icon; + info.labelRes = target.info.labelRes; + info.nonLocalizedLabel = target.info.nonLocalizedLabel; + info.launchMode = target.info.launchMode; + info.processName = target.info.processName; + info.screenOrientation = target.info.screenOrientation; + info.taskAffinity = target.info.taskAffinity; + info.theme = target.info.theme; + + Activity a = new Activity(mParseActivityAliasArgs, info); + if (outError[0] != null) { sa.recycle(); return null; } @@ -1482,9 +1634,6 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); } - a.component = new ComponentName(owner.applicationInfo.packageName, - a.info.name); - String str; str = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestActivityAlias_permission); @@ -1548,14 +1697,22 @@ public class PackageParser { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestProvider); - Provider p = new Provider(owner); - - if (!parseComponentInfo(owner, flags, p.info, outError, "", sa, - com.android.internal.R.styleable.AndroidManifestProvider_name, - com.android.internal.R.styleable.AndroidManifestProvider_label, - com.android.internal.R.styleable.AndroidManifestProvider_icon, - com.android.internal.R.styleable.AndroidManifestProvider_process, - com.android.internal.R.styleable.AndroidManifestProvider_enabled)) { + if (mParseProviderArgs == null) { + mParseProviderArgs = new ParseComponentArgs(owner, outError, + com.android.internal.R.styleable.AndroidManifestProvider_name, + com.android.internal.R.styleable.AndroidManifestProvider_label, + com.android.internal.R.styleable.AndroidManifestProvider_icon, + mSeparateProcesses, + com.android.internal.R.styleable.AndroidManifestProvider_process, + com.android.internal.R.styleable.AndroidManifestProvider_enabled); + mParseProviderArgs.tag = ""; + } + + mParseProviderArgs.sa = sa; + mParseProviderArgs.flags = flags; + + Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); + if (outError[0] != null) { sa.recycle(); return null; } @@ -1563,9 +1720,6 @@ public class PackageParser { p.info.exported = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestProvider_exported, true); - p.component = new ComponentName(owner.applicationInfo.packageName, - p.info.name); - String cpname = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestProvider_authorities); @@ -1706,14 +1860,22 @@ public class PackageParser { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestService); - Service s = new Service(owner); - - if (!parseComponentInfo(owner, flags, s.info, outError, "", sa, - com.android.internal.R.styleable.AndroidManifestService_name, - com.android.internal.R.styleable.AndroidManifestService_label, - com.android.internal.R.styleable.AndroidManifestService_icon, - com.android.internal.R.styleable.AndroidManifestService_process, - com.android.internal.R.styleable.AndroidManifestService_enabled)) { + if (mParseServiceArgs == null) { + mParseServiceArgs = new ParseComponentArgs(owner, outError, + com.android.internal.R.styleable.AndroidManifestService_name, + com.android.internal.R.styleable.AndroidManifestService_label, + com.android.internal.R.styleable.AndroidManifestService_icon, + mSeparateProcesses, + com.android.internal.R.styleable.AndroidManifestService_process, + com.android.internal.R.styleable.AndroidManifestService_enabled); + mParseServiceArgs.tag = ""; + } + + mParseServiceArgs.sa = sa; + mParseServiceArgs.flags = flags; + + Service s = new Service(mParseServiceArgs, new ServiceInfo()); + if (outError[0] != null) { sa.recycle(); return null; } @@ -1725,9 +1887,6 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestService_exported, false); } - s.component = new ComponentName(owner.applicationInfo.packageName, - s.info.name); - String str = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestService_permission); if (str == null) { @@ -2035,12 +2194,12 @@ public class PackageParser { // We store the application meta-data independently to avoid multiple unwanted references public Bundle mAppMetaData = null; + public final ArrayList supportsDensityList = new ArrayList(); + public int[] supportsDensities = null; + // If this is a 3rd party app, this is the path of the zip file. public String mPath; - // True if this package is part of the system image. - public boolean mSystem; - // The version code declared for this package. public int mVersionCode; @@ -2084,16 +2243,75 @@ public class PackageParser { public static class Component { public final Package owner; - public final ArrayList intents = new ArrayList(0); - public ComponentName component; + public final ArrayList intents; + public final ComponentName component; + public final String componentShortName; public Bundle metaData; public Component(Package _owner) { owner = _owner; + intents = null; + component = null; + componentShortName = null; + } + + public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { + owner = args.owner; + intents = new ArrayList(0); + String name = args.sa.getNonResourceString(args.nameRes); + if (name == null) { + component = null; + componentShortName = null; + args.outError[0] = args.tag + " does not specify android:name"; + return; + } + + outInfo.name + = buildClassName(owner.applicationInfo.packageName, name, args.outError); + if (outInfo.name == null) { + component = null; + componentShortName = null; + args.outError[0] = args.tag + " does not have valid android:name"; + return; + } + + component = new ComponentName(owner.applicationInfo.packageName, + outInfo.name); + componentShortName = component.flattenToShortString(); + + int iconVal = args.sa.getResourceId(args.iconRes, 0); + if (iconVal != 0) { + outInfo.icon = iconVal; + outInfo.nonLocalizedLabel = null; + } + + TypedValue v = args.sa.peekValue(args.labelRes); + if (v != null && (outInfo.labelRes=v.resourceId) == 0) { + outInfo.nonLocalizedLabel = v.coerceToString(); + } + + outInfo.packageName = owner.packageName; + } + + public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { + this(args, (PackageItemInfo)outInfo); + if (args.outError[0] != null) { + return; + } + + if (args.processRes != 0) { + outInfo.processName = buildProcessName(owner.applicationInfo.packageName, + owner.applicationInfo.processName, args.sa.getNonResourceString(args.processRes), + args.flags, args.sepProcesses, args.outError); + } + outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); } public Component(Component clone) { owner = clone.owner; + intents = clone.intents; + component = clone.component; + componentShortName = clone.componentShortName; metaData = clone.metaData; } } @@ -2149,6 +2367,10 @@ public class PackageParser { && p.usesLibraryFiles != null) { return true; } + if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0 + && p.supportsDensities != null) { + return true; + } return false; } @@ -2166,6 +2388,9 @@ public class PackageParser { if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { ai.sharedLibraryFiles = p.usesLibraryFiles; } + if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) { + ai.supportsDensities = p.supportsDensities; + } return ai; } @@ -2192,14 +2417,14 @@ public class PackageParser { } public final static class Activity extends Component { - public final ActivityInfo info = - new ActivityInfo(); + public final ActivityInfo info; - public Activity(Package _owner) { - super(_owner); - info.applicationInfo = owner.applicationInfo; + public Activity(final ParseComponentArgs args, final ActivityInfo _info) { + super(args, _info); + info = _info; + info.applicationInfo = args.owner.applicationInfo; } - + public String toString() { return "Activity{" + Integer.toHexString(System.identityHashCode(this)) @@ -2221,14 +2446,14 @@ public class PackageParser { } public final static class Service extends Component { - public final ServiceInfo info = - new ServiceInfo(); + public final ServiceInfo info; - public Service(Package _owner) { - super(_owner); - info.applicationInfo = owner.applicationInfo; + public Service(final ParseComponentArgs args, final ServiceInfo _info) { + super(args, _info); + info = _info; + info.applicationInfo = args.owner.applicationInfo; } - + public String toString() { return "Service{" + Integer.toHexString(System.identityHashCode(this)) @@ -2252,13 +2477,13 @@ public class PackageParser { public final ProviderInfo info; public boolean syncable; - public Provider(Package _owner) { - super(_owner); - info = new ProviderInfo(); - info.applicationInfo = owner.applicationInfo; + public Provider(final ParseComponentArgs args, final ProviderInfo _info) { + super(args, _info); + info = _info; + info.applicationInfo = args.owner.applicationInfo; syncable = false; } - + public Provider(Provider existingProvider) { super(existingProvider); this.info = existingProvider.info; @@ -2291,13 +2516,13 @@ public class PackageParser { } public final static class Instrumentation extends Component { - public final InstrumentationInfo info = - new InstrumentationInfo(); + public final InstrumentationInfo info; - public Instrumentation(Package _owner) { - super(_owner); + public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { + super(args, _info); + info = _info; } - + public String toString() { return "Instrumentation{" + Integer.toHexString(System.identityHashCode(this)) diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 956b15a788285c28637486ade8f7a265994911da..bb3486c205545776e0c3bbbfe568384aa58c9f12 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -144,11 +144,29 @@ public final class Configuration implements Parcelable, Comparable SparseArray emptySparseArray() { + return (SparseArray) EMPTY_ARRAY; + } + /** * This exception is thrown by the resource APIs when a requested resource * can not be found. @@ -107,11 +126,27 @@ public class Resources { */ public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) { + this(assets, metrics, config, true); + } + + /** + * Create a resource with an additional flag for preloaded + * drawable cache. Used by {@link ActivityThread}. + * + * @hide + */ + public Resources(AssetManager assets, DisplayMetrics metrics, + Configuration config, boolean usePreloadedCache) { mAssets = assets; mConfiguration.setToDefaults(); mMetrics.setToDefaults(); updateConfiguration(config, metrics); assets.ensureStringBlocks(); + if (usePreloadedCache) { + mPreloadedDrawables = sPreloadedDrawables; + } else { + mPreloadedDrawables = emptySparseArray(); + } } /** @@ -1218,6 +1253,7 @@ public class Resources { mMetrics.setTo(metrics); } mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; + String locale = null; if (mConfiguration.locale != null) { locale = mConfiguration.locale.getLanguage(); @@ -1653,7 +1689,7 @@ public class Resources { cs = dr.getConstantState(); if (cs != null) { if (mPreloading) { - mPreloadedDrawables.put(key, cs); + sPreloadedDrawables.put(key, cs); } else { synchronized (mTmpValue) { //Log.i(TAG, "Saving cached drawable @ #" + @@ -1883,6 +1919,6 @@ public class Resources { mMetrics.setToDefaults(); updateConfiguration(null, null); mAssets.ensureStringBlocks(); + mPreloadedDrawables = sPreloadedDrawables; } } - diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java index 519a81c24385d2fd319a56cef678253df5658104..ab7c827cc7c86e0853f0dba203b785e149a981f8 100644 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java @@ -486,12 +486,20 @@ public class SQLiteQueryBuilder String userColumn = projectionIn[i]; String column = mProjectionMap.get(userColumn); - if (column == null) { - throw new IllegalArgumentException( - "Invalid column " + projectionIn[i]); - } else { + if (column != null) { projection[i] = column; + continue; } + + if (userColumn.contains(" AS ") + || userColumn.contains(" as ")) { + /* A column alias already exist */ + projection[i] = userColumn; + continue; + } + + throw new IllegalArgumentException("Invalid column " + + projectionIn[i]); } return projection; } else { diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java index 54457c215cc2726c93484432312292d036b41a02..95fa0a265d152258a76fe0cdc276e06b9f649333 100644 --- a/core/java/android/ddm/DdmHandleHeap.java +++ b/core/java/android/ddm/DdmHandleHeap.java @@ -20,17 +20,20 @@ import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; import org.apache.harmony.dalvik.ddmc.DdmVmInternal; +import android.os.Debug; import android.util.Config; import android.util.Log; +import java.io.IOException; import java.nio.ByteBuffer; /** - * Handle thread-related traffic. + * Handle native and virtual heap requests. */ public class DdmHandleHeap extends ChunkHandler { public static final int CHUNK_HPIF = type("HPIF"); public static final int CHUNK_HPSG = type("HPSG"); + public static final int CHUNK_HPDU = type("HPDU"); public static final int CHUNK_NHSG = type("NHSG"); public static final int CHUNK_HPGC = type("HPGC"); public static final int CHUNK_REAE = type("REAE"); @@ -49,6 +52,7 @@ public class DdmHandleHeap extends ChunkHandler { public static void register() { DdmServer.registerHandler(CHUNK_HPIF, mInstance); DdmServer.registerHandler(CHUNK_HPSG, mInstance); + DdmServer.registerHandler(CHUNK_HPDU, mInstance); DdmServer.registerHandler(CHUNK_NHSG, mInstance); DdmServer.registerHandler(CHUNK_HPGC, mInstance); DdmServer.registerHandler(CHUNK_REAE, mInstance); @@ -80,6 +84,8 @@ public class DdmHandleHeap extends ChunkHandler { return handleHPIF(request); } else if (type == CHUNK_HPSG) { return handleHPSGNHSG(request, false); + } else if (type == CHUNK_HPDU) { + return handleHPDU(request); } else if (type == CHUNK_NHSG) { return handleHPSGNHSG(request, true); } else if (type == CHUNK_HPGC) { @@ -97,7 +103,7 @@ public class DdmHandleHeap extends ChunkHandler { } /* - * Handle a "HeaP InFo request". + * Handle a "HeaP InFo" request. */ private Chunk handleHPIF(Chunk request) { ByteBuffer in = wrapChunk(request); @@ -136,6 +142,40 @@ public class DdmHandleHeap extends ChunkHandler { } } + /* + * Handle a "HeaP DUmp" request. + * + * This currently just returns a result code. We could pull up + * the entire contents of the file and return them, but hprof dump + * files can be a few megabytes. + */ + private Chunk handleHPDU(Chunk request) { + ByteBuffer in = wrapChunk(request); + byte result; + + /* get the filename for the output file */ + int len = in.getInt(); + String fileName = getString(in, len); + if (Config.LOGD) + Log.d("ddm-heap", "Heap dump: file='" + fileName + "'"); + + try { + Debug.dumpHprofData(fileName); + result = 0; + } catch (UnsupportedOperationException uoe) { + Log.w("ddm-heap", "hprof dumps not supported in this VM"); + result = -1; + } catch (IOException ioe) { + result = -1; + } catch (RuntimeException ioe) { + result = -1; + } + + /* create a non-empty reply so the handler fires on completion */ + byte[] reply = { result }; + return new Chunk(CHUNK_HPDU, reply, 0, reply.length); + } + /* * Handle a "HeaP Garbage Collection" request. */ diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java index e4d630e4880a600da39833f5d4398ad5d6a4b920..c5d591f633a91147c5669cccfa2e7353836e49f8 100644 --- a/core/java/android/ddm/DdmHandleHello.java +++ b/core/java/android/ddm/DdmHandleHello.java @@ -26,12 +26,13 @@ import android.os.Debug; import java.nio.ByteBuffer; /** - * Handle a HELO chunk. + * Handle "hello" messages and feature discovery. */ public class DdmHandleHello extends ChunkHandler { public static final int CHUNK_HELO = type("HELO"); public static final int CHUNK_WAIT = type("WAIT"); + public static final int CHUNK_FEAT = type("FEAT"); private static DdmHandleHello mInstance = new DdmHandleHello(); @@ -44,6 +45,7 @@ public class DdmHandleHello extends ChunkHandler { */ public static void register() { DdmServer.registerHandler(CHUNK_HELO, mInstance); + DdmServer.registerHandler(CHUNK_FEAT, mInstance); } /** @@ -73,12 +75,27 @@ public class DdmHandleHello extends ChunkHandler { } /** - * Handle a chunk of data. We're only registered for "HELO". + * Handle a chunk of data. */ public Chunk handleChunk(Chunk request) { if (Config.LOGV) - Log.v("ddm-hello", "Handling " + name(request.type) + " chunk"); + Log.v("ddm-heap", "Handling " + name(request.type) + " chunk"); + int type = request.type; + + if (type == CHUNK_HELO) { + return handleHELO(request); + } else if (type == CHUNK_FEAT) { + return handleFEAT(request); + } else { + throw new RuntimeException("Unknown packet " + + ChunkHandler.name(type)); + } + } + /* + * Handle introductory packet. + */ + private Chunk handleHELO(Chunk request) { if (false) return createFailChunk(123, "This is a test"); @@ -125,6 +142,34 @@ public class DdmHandleHello extends ChunkHandler { return reply; } + /* + * Handle request for list of supported features. + */ + private Chunk handleFEAT(Chunk request) { + // TODO: query the VM to ensure that support for these features + // is actually compiled in + final String[] features = { + "hprof-heap-dump", "method-trace-profiling" + }; + + if (Config.LOGD) + Log.d("ddm-heap", "Got feature list request"); + + int size = 4 + 4 * features.length; + for (int i = features.length-1; i >= 0; i--) + size += features[i].length() * 2; + + ByteBuffer out = ByteBuffer.allocate(size); + out.order(ChunkHandler.CHUNK_ORDER); + out.putInt(features.length); + for (int i = features.length-1; i >= 0; i--) { + out.putInt(features[i].length()); + putString(out, features[i]); + } + + return new Chunk(CHUNK_FEAT, out); + } + /** * Send up a WAIT chunk. The only currently defined value for "reason" * is zero, which means "waiting for a debugger". diff --git a/core/java/android/ddm/DdmHandleProfiling.java b/core/java/android/ddm/DdmHandleProfiling.java new file mode 100644 index 0000000000000000000000000000000000000000..beed50507fa28712abd0a24431a93398d5719a89 --- /dev/null +++ b/core/java/android/ddm/DdmHandleProfiling.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.ddm; + +import org.apache.harmony.dalvik.ddmc.Chunk; +import org.apache.harmony.dalvik.ddmc.ChunkHandler; +import org.apache.harmony.dalvik.ddmc.DdmServer; +import android.os.Debug; +import android.util.Config; +import android.util.Log; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Handle profiling requests. + */ +public class DdmHandleProfiling extends ChunkHandler { + + public static final int CHUNK_MPRS = type("MPRS"); + public static final int CHUNK_MPRE = type("MPRE"); + public static final int CHUNK_MPRQ = type("MPRQ"); + + private static DdmHandleProfiling mInstance = new DdmHandleProfiling(); + + + /* singleton, do not instantiate */ + private DdmHandleProfiling() {} + + /** + * Register for the messages we're interested in. + */ + public static void register() { + DdmServer.registerHandler(CHUNK_MPRS, mInstance); + DdmServer.registerHandler(CHUNK_MPRE, mInstance); + DdmServer.registerHandler(CHUNK_MPRQ, mInstance); + } + + /** + * Called when the DDM server connects. The handler is allowed to + * send messages to the server. + */ + public void connected() {} + + /** + * Called when the DDM server disconnects. Can be used to disable + * periodic transmissions or clean up saved state. + */ + public void disconnected() {} + + /** + * Handle a chunk of data. + */ + public Chunk handleChunk(Chunk request) { + if (Config.LOGV) + Log.v("ddm-heap", "Handling " + name(request.type) + " chunk"); + int type = request.type; + + if (type == CHUNK_MPRS) { + return handleMPRS(request); + } else if (type == CHUNK_MPRE) { + return handleMPRE(request); + } else if (type == CHUNK_MPRQ) { + return handleMPRQ(request); + } else { + throw new RuntimeException("Unknown packet " + + ChunkHandler.name(type)); + } + } + + /* + * Handle a "Method PRofiling Start" request. + */ + private Chunk handleMPRS(Chunk request) { + ByteBuffer in = wrapChunk(request); + + int bufferSize = in.getInt(); + int flags = in.getInt(); + int len = in.getInt(); + String fileName = getString(in, len); + if (Config.LOGV) + Log.v("ddm-heap", "Method profiling start: filename='" + fileName + + "', size=" + bufferSize + ", flags=" + flags); + + try { + Debug.startMethodTracing(fileName, bufferSize, flags); + return null; // empty response + } catch (RuntimeException re) { + return createFailChunk(1, re.getMessage()); + } + } + + /* + * Handle a "Method PRofiling End" request. + */ + private Chunk handleMPRE(Chunk request) { + byte result; + + try { + Debug.stopMethodTracing(); + result = 0; + } catch (RuntimeException re) { + Log.w("ddm-heap", "Method profiling end failed: " + + re.getMessage()); + result = 1; + } + + /* create a non-empty reply so the handler fires on completion */ + byte[] reply = { result }; + return new Chunk(CHUNK_MPRE, reply, 0, reply.length); + } + + /* + * Handle a "Method PRofiling Query" request. + */ + private Chunk handleMPRQ(Chunk request) { + int result = Debug.isMethodTracingActive() ? 1 : 0; + + /* create a non-empty reply so the handler fires on completion */ + byte[] reply = { (byte) result }; + return new Chunk(CHUNK_MPRQ, reply, 0, reply.length); + } +} + diff --git a/core/java/android/ddm/DdmRegister.java b/core/java/android/ddm/DdmRegister.java index b7f1ab8dbb353fb641bba70a735ebbc59c9fdb04..debf189bb1d0953c7f5b7b0cc4b5ed309f1cb31e 100644 --- a/core/java/android/ddm/DdmRegister.java +++ b/core/java/android/ddm/DdmRegister.java @@ -50,6 +50,7 @@ public class DdmRegister { DdmHandleThread.register(); DdmHandleHeap.register(); DdmHandleNativeHeap.register(); + DdmHandleProfiling.register(); DdmHandleExit.register(); DdmServer.registrationComplete(); diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 106c9200b680c9fd020b13f0c2723ed0b4ed4a11..ca579b6b501b6965588612078eb02876befd1fb6 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -405,8 +405,6 @@ public class Camera { * @param params the Parameters to use for this Camera service */ public void setParameters(Parameters params) { - Log.e(TAG, "setParameters()"); - //params.dump(); native_setParameters(params.flatten()); } @@ -416,7 +414,6 @@ public class Camera { public Parameters getParameters() { Parameters p = new Parameters(); String s = native_getParameters(); - Log.e(TAG, "_getParameters: " + s); p.unflatten(s); return p; } diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 0c88a2e04072ac4689b39f7b0b52b75774859e1e..67df23b270a4b16ab804e62c517cd4ab95178ba3 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -43,7 +43,7 @@ import java.util.List; * class by calling {@link android.content.Context#getSystemService(java.lang.String) * Context.getSystemService()} with an argument of {@link android.content.Context#SENSOR_SERVICE}. */ -public class SensorManager extends IRotationWatcher.Stub +public class SensorManager { private static final String TAG = "SensorManager"; private static final float[] mTempMatrix = new float[16]; @@ -475,7 +475,13 @@ public class SensorManager extends IRotationWatcher.Stub // if it's null we're running in the system process // which won't get the rotated values try { - sRotation = sWindowManager.watchRotation(this); + sRotation = sWindowManager.watchRotation( + new IRotationWatcher.Stub() { + public void onRotationChanged(int rotation) { + SensorManager.this.onRotationChanged(rotation); + } + } + ); } catch (RemoteException e) { } } @@ -1386,7 +1392,7 @@ public class SensorManager extends IRotationWatcher.Stub } } } - + class LmsFilter { private static final int SENSORS_RATE_MS = 20; private static final int COUNT = 12; @@ -1454,7 +1460,7 @@ public class SensorManager extends IRotationWatcher.Stub } } - + private static native void nativeClassInit(); private static native int sensors_module_init(); diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java index 6a560ce0150bedff3917561567d6fb565ecd15ee..fea63be795b2525ef77d3ccbbe197612a4ca3335 100755 --- a/core/java/android/inputmethodservice/Keyboard.java +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -27,8 +27,7 @@ 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 android.util.DisplayMetrics; import java.io.IOException; import java.util.ArrayList; @@ -510,10 +509,11 @@ public class Keyboard { * @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(); + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + mDisplayWidth = dm.widthPixels; + mDisplayHeight = dm.heightPixels; + //Log.v(TAG, "keyboard's display metrics:" + dm); + mDefaultHorizontalGap = 0; mDefaultWidth = mDisplayWidth / 10; mDefaultVerticalGap = 0; diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 65c989377e8649507c91237f849efc1caf394af1..8b474d567ac90add2d0479fbbec5c3f712c2918d 100755 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -407,7 +407,7 @@ public class KeyboardView extends View implements View.OnClickListener { // Release buffer, just in case the new keyboard has a different size. // It will be reallocated on the next draw. mBuffer = null; - invalidateAll(); + invalidateAllKeys(); computeProximityThreshold(keyboard); mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views } @@ -431,7 +431,7 @@ public class KeyboardView extends View implements View.OnClickListener { if (mKeyboard != null) { if (mKeyboard.setShifted(shifted)) { // The whole keyboard probably needs to be redrawn - invalidateAll(); + invalidateAllKeys(); return true; } } @@ -573,7 +573,7 @@ public class KeyboardView extends View implements View.OnClickListener { if (mBuffer == null) { mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBuffer); - invalidateAll(); + invalidateAllKeys(); } final Canvas canvas = mCanvas; canvas.clipRect(mDirtyRect, Op.REPLACE); @@ -874,13 +874,27 @@ public class KeyboardView extends View implements View.OnClickListener { mPreviewText.setVisibility(VISIBLE); } - private void invalidateAll() { + /** + * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient + * because the keyboard renders the keys to an off-screen buffer and an invalidate() only + * draws the cached buffer. + * @see #invalidateKey(int) + */ + public void invalidateAllKeys() { mDirtyRect.union(0, 0, getWidth(), getHeight()); mDrawPending = true; invalidate(); } - - private void invalidateKey(int keyIndex) { + + /** + * Invalidates a key so that it will be redrawn on the next repaint. Use this method if only + * one key is changing it's content. Any changes that affect the position or size of the key + * may not be honored. + * @param keyIndex the index of the key in the attached {@link Keyboard}. + * @see #invalidateAllKeys + */ + public void invalidateKey(int keyIndex) { + if (mKeys == null) return; if (keyIndex < 0 || keyIndex >= mKeys.length) { return; } @@ -991,7 +1005,7 @@ public class KeyboardView extends View implements View.OnClickListener { mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); mMiniKeyboardOnScreen = true; //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me)); - invalidateAll(); + invalidateAllKeys(); return true; } return false; @@ -1164,7 +1178,7 @@ public class KeyboardView extends View implements View.OnClickListener { if (mPopupKeyboard.isShowing()) { mPopupKeyboard.dismiss(); mMiniKeyboardOnScreen = false; - invalidateAll(); + invalidateAllKeys(); } } diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 1d939e10068c3fb597c1eae8b8c94bb81ec2f778..1064fb64fb942b21875ca642afb66996abeaf52f 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -117,28 +117,28 @@ public class MobileDataStateTracker extends NetworkStateTracker { mMobileDataState = state; switch (state) { - case DISCONNECTED: - setDetailedState(DetailedState.DISCONNECTED, reason, apnName); - if (mInterfaceName != null) { - NetworkUtils.resetConnections(mInterfaceName); - } - mInterfaceName = null; - mDefaultGatewayAddr = 0; - break; - case CONNECTING: - setDetailedState(DetailedState.CONNECTING, reason, apnName); - break; - case SUSPENDED: - setDetailedState(DetailedState.SUSPENDED, reason, apnName); - break; - case CONNECTED: - mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); - if (mInterfaceName == null) { - Log.d(TAG, "CONNECTED event did not supply interface name."); - } - setupDnsProperties(); - setDetailedState(DetailedState.CONNECTED, reason, apnName); - break; + case DISCONNECTED: + setDetailedState(DetailedState.DISCONNECTED, reason, apnName); + if (mInterfaceName != null) { + NetworkUtils.resetConnections(mInterfaceName); + } + mInterfaceName = null; + mDefaultGatewayAddr = 0; + break; + case CONNECTING: + setDetailedState(DetailedState.CONNECTING, reason, apnName); + break; + case SUSPENDED: + setDetailedState(DetailedState.SUSPENDED, reason, apnName); + break; + case CONNECTED: + mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); + if (mInterfaceName == null) { + Log.d(TAG, "CONNECTED event did not supply interface name."); + } + setupDnsProperties(); + setDetailedState(DetailedState.CONNECTED, reason, apnName); + break; } } } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { @@ -199,7 +199,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { */ public boolean isAvailable() { getPhoneService(false); - + /* * If the phone process has crashed in the past, we'll get a * RemoteException and need to re-reference the service. @@ -214,7 +214,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { if (retry == 0) getPhoneService(true); } } - + return false; } @@ -241,18 +241,28 @@ public class MobileDataStateTracker extends NetworkStateTracker { * for this network. */ public String getTcpBufferSizesPropName() { - String networkTypeStr = "unknown"; + String networkTypeStr = "unknown"; TelephonyManager tm = new TelephonyManager(mContext); + //TODO We have to edit the parameter for getNetworkType regarding CDMA switch(tm.getNetworkType()) { - case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_GPRS: networkTypeStr = "gprs"; break; - case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_EDGE: networkTypeStr = "edge"; break; - case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_UMTS: networkTypeStr = "umts"; break; + case TelephonyManager.NETWORK_TYPE_CDMA: + networkTypeStr = "cdma"; + break; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + networkTypeStr = "evdo"; + break; + case TelephonyManager.NETWORK_TYPE_EVDO_A: + networkTypeStr = "evdo"; + break; } return "net.tcp.buffersize." + networkTypeStr; } @@ -281,7 +291,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { if (retry == 0) getPhoneService(true); } } - + Log.w(TAG, "Failed to tear down mobile data connectivity"); return false; } @@ -330,7 +340,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { "Ignoring mobile radio request because could not acquire PhoneService"); break; } - + try { return mPhoneService.setRadio(turnOn); } catch (RemoteException e) { @@ -344,9 +354,10 @@ public class MobileDataStateTracker extends NetworkStateTracker { /** * Tells the phone sub-system that the caller wants to - * begin 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. + * begin using the named feature. The only supported features at + * this time are {@code Phone.FEATURE_ENABLE_MMS}, which allows an application + * to specify that it wants to send and/or receive MMS data, and + * {@code Phone.FEATURE_ENABLE_SUPL}, which is used for Assisted GPS. * @param feature the name of the feature to be used * @param callingPid the process ID of the process that is issuing this request * @param callingUid the user ID of the process that is issuing this request @@ -366,6 +377,8 @@ public class MobileDataStateTracker extends NetworkStateTracker { if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { mLastCallingPid = callingPid; return setEnableApn(Phone.APN_TYPE_MMS, true); + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { + return setEnableApn(Phone.APN_TYPE_SUPL, true); } else { return -1; } @@ -386,6 +399,8 @@ public class MobileDataStateTracker extends NetworkStateTracker { public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { return setEnableApn(Phone.APN_TYPE_MMS, false); + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { + return setEnableApn(Phone.APN_TYPE_SUPL, false); } else { return -1; } diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 9f07c0a2c5b04d425aadd4bd598e9e68768b48de..66eefb26af97fbafcee49d6a261bbffcfd971a99 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -30,6 +30,9 @@ import junit.framework.Assert; */ final public class Proxy { + // Set to true to enable extra debugging. + static final private boolean DEBUG = false; + static final public String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; @@ -49,7 +52,7 @@ final public class Proxy { if (host != null) { int i = host.indexOf(':'); if (i == -1) { - if (android.util.Config.DEBUG) { + if (DEBUG) { Assert.assertTrue(host.length() == 0); } return null; @@ -73,12 +76,12 @@ final public class Proxy { if (host != null) { int i = host.indexOf(':'); if (i == -1) { - if (android.util.Config.DEBUG) { + if (DEBUG) { Assert.assertTrue(host.length() == 0); } return -1; } - if (android.util.Config.DEBUG) { + if (DEBUG) { Assert.assertTrue(i < host.length()); } return Integer.parseInt(host.substring(i+1)); diff --git a/core/java/android/net/http/CertificateValidatorCache.java b/core/java/android/net/http/CertificateValidatorCache.java index 54a1dbe51aa81ec5a89c12c93dc884c6db53724f..47661d5e76234983d7fc328a20e1b919b082f7db 100644 --- a/core/java/android/net/http/CertificateValidatorCache.java +++ b/core/java/android/net/http/CertificateValidatorCache.java @@ -236,15 +236,17 @@ class CertificateValidatorCache { } } - int hashLength = secureHash.length; - if (secureHash != null && 0 < hashLength) { - if (hashLength == mHash.length) { - for (int i = 0; i < hashLength; ++i) { - if (secureHash[i] != mHash[i]) { - return false; + if (secureHash != null) { + int hashLength = secureHash.length; + if (0 < hashLength) { + if (hashLength == mHash.length) { + for (int i = 0; i < hashLength; ++i) { + if (secureHash[i] != mHash[i]) { + return false; + } } + return true; } - return true; } } diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index ee4e8974b5c7c50ff97d20d3af6f27f25a725bb2..6c135825a99fb52f44cf051175e627fcfce6a3ae 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -37,7 +37,7 @@ import java.util.concurrent.atomic.AtomicInteger; * 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.

    + * processProgress and end.

    * *

    Usage

    *

    AsyncTask must be subclassed to be used. The subclass will override at least @@ -85,7 +85,7 @@ import java.util.concurrent.atomic.AtomicInteger; *

    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

    diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 17594d410d701c23f989a52c6009fbdd352c5924..8a0fd58530b04f0b84dfa394f277494f5ce7ba0b 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -61,6 +61,13 @@ public abstract class BatteryStats implements Parcelable { */ public static final int SCAN_WIFI_LOCK = 6; + /** + * A constant indicating a wifi multicast timer + * + * {@hide} + */ + public static final int WIFI_MULTICAST_ENABLED = 7; + /** * Include all of the data in the stats, including previously saved data. */ @@ -80,35 +87,40 @@ public abstract class BatteryStats implements Parcelable { * Include only the run since the last time the device was unplugged in the stats. */ public static final int STATS_UNPLUGGED = 3; + + // NOTE: Update this list if you add/change any stats above. + // These characters are supposed to represent "total", "last", "current", + // and "unplugged". They were shortened for effeciency sake. + private static final String[] STAT_NAMES = { "t", "l", "c", "u" }; /** * Bump the version on this if the checkin format changes. */ - private static final int BATTERY_STATS_CHECKIN_VERSION = 3; + private static final int BATTERY_STATS_CHECKIN_VERSION = 5; private static final long BYTES_PER_KB = 1024; private static final long BYTES_PER_MB = 1048576; // 1024^2 private static final long BYTES_PER_GB = 1073741824; //1024^3 - // TODO: Update this list if you add/change any stats above. - private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" }; private static final String APK_DATA = "apk"; - private static final String PROCESS_DATA = "process"; - private static final String SENSOR_DATA = "sensor"; - private static final String WAKELOCK_DATA = "wakelock"; - private static final String NETWORK_DATA = "network"; - private static final String USER_ACTIVITY_DATA = "useract"; - private static final String BATTERY_DATA = "battery"; - private static final String WIFI_LOCK_DATA = "wifilock"; - private static final String MISC_DATA = "misc"; - private static final String SCREEN_BRIGHTNESS_DATA = "brightness"; - private static final String SIGNAL_STRENGTH_TIME_DATA = "sigtime"; - private static final String SIGNAL_STRENGTH_COUNT_DATA = "sigcnt"; - private static final String DATA_CONNECTION_TIME_DATA = "dconntime"; - private static final String DATA_CONNECTION_COUNT_DATA = "dconncnt"; - - private final StringBuilder mFormatBuilder = new StringBuilder(8); + private static final String PROCESS_DATA = "pr"; + private static final String SENSOR_DATA = "sr"; + private static final String WAKELOCK_DATA = "wl"; + private static final String KERNEL_WAKELOCK_DATA = "kwl"; + private static final String NETWORK_DATA = "nt"; + private static final String USER_ACTIVITY_DATA = "ua"; + private static final String BATTERY_DATA = "bt"; + private static final String BATTERY_LEVEL_DATA = "lv"; + private static final String WIFI_LOCK_DATA = "wfl"; + private static final String MISC_DATA = "m"; + private static final String SCREEN_BRIGHTNESS_DATA = "br"; + private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt"; + private static final String SIGNAL_STRENGTH_COUNT_DATA = "sgc"; + private static final String DATA_CONNECTION_TIME_DATA = "dct"; + private static final String DATA_CONNECTION_COUNT_DATA = "dcc"; + + private final StringBuilder mFormatBuilder = new StringBuilder(32); private final Formatter mFormatter = new Formatter(mFormatBuilder); /** @@ -122,7 +134,7 @@ public abstract class BatteryStats implements Parcelable { * * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT */ - public abstract int getCount(int which); + public abstract int getCountLocked(int which); /** * Temporary for debugging. @@ -141,7 +153,7 @@ public abstract class BatteryStats implements Parcelable { * * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT */ - public abstract int getCount(int which); + public abstract int getCountLocked(int which); /** * Returns the total time in microseconds associated with this Timer for the @@ -151,7 +163,7 @@ public abstract class BatteryStats implements Parcelable { * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT * @return a time in microseconds */ - public abstract long getTotalTime(long batteryRealtime, int which); + public abstract long getTotalTimeLocked(long batteryRealtime, int which); /** * Temporary for debugging. @@ -220,9 +232,13 @@ public abstract class BatteryStats implements Parcelable { public abstract void noteFullWifiLockReleasedLocked(); public abstract void noteScanWifiLockAcquiredLocked(); public abstract void noteScanWifiLockReleasedLocked(); + public abstract void noteWifiMulticastEnabledLocked(); + public abstract void noteWifiMulticastDisabledLocked(); public abstract long getWifiTurnedOnTime(long batteryRealtime, int which); public abstract long getFullWifiLockTime(long batteryRealtime, int which); public abstract long getScanWifiLockTime(long batteryRealtime, int which); + public abstract long getWifiMulticastTime(long batteryRealtime, + int which); /** * Note that these must match the constants in android.os.LocalPowerManager. @@ -472,15 +488,16 @@ public abstract class BatteryStats implements Parcelable { public abstract long getBatteryRealtime(long curTime); /** - * Returns the battery percentage level at the last time the device was unplugged from power, - * or the last time it was booted while unplugged. + * Returns the battery percentage level at the last time the device was unplugged from power, or + * the last time it booted on battery power. */ - public abstract int getUnpluggedStartLevel(); + public abstract int getDischargeStartLevel(); /** - * Returns the battery percentage level at the last time the device was plugged into power. + * Returns the current battery percentage level if we are in a discharge cycle, otherwise + * returns the level at the last plug event. */ - public abstract int getPluggedStartLevel(); + public abstract int getDischargeCurrentLevel(); /** * Returns the total, last, or current battery uptime in microseconds. @@ -513,8 +530,10 @@ public abstract class BatteryStats implements Parcelable { * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. */ public abstract long computeRealtime(long curTime, int which); + + public abstract Map getKernelWakelockStats(); - private final static void formatTime(StringBuilder out, long seconds) { + private final static void formatTimeRaw(StringBuilder out, long seconds) { long days = seconds / (60 * 60 * 24); if (days != 0) { out.append(days); @@ -542,22 +561,18 @@ public abstract class BatteryStats implements Parcelable { } } - private final static String formatTime(long time) { + private final static void formatTime(StringBuilder sb, long time) { long sec = time / 100; - StringBuilder sb = new StringBuilder(); - formatTime(sb, sec); + formatTimeRaw(sb, sec); sb.append((time - (sec * 100)) * 10); sb.append("ms "); - return sb.toString(); } - private final static String formatTimeMs(long time) { + private final static void formatTimeMs(StringBuilder sb, long time) { long sec = time / 1000; - StringBuilder sb = new StringBuilder(); - formatTime(sb, sec); + formatTimeRaw(sb, sec); sb.append(time - (sec * 1000)); sb.append("ms "); - return sb.toString(); } private final String formatRatioLocked(long num, long den) { @@ -602,14 +617,14 @@ public abstract class BatteryStats implements Parcelable { if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTimeMicros = timer.getTotalTime(batteryRealtime, which); + long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which); long totalTimeMillis = (totalTimeMicros + 500) / 1000; - int count = timer.getCount(which); + int count = timer.getCountLocked(which); if (totalTimeMillis != 0) { sb.append(linePrefix); - sb.append(formatTimeMs(totalTimeMillis)); - sb.append(name); + formatTimeMs(sb, totalTimeMillis); + if (name != null) sb.append(name); sb.append(' '); sb.append('('); sb.append(count); @@ -632,18 +647,17 @@ public abstract class BatteryStats implements Parcelable { * @return the line prefix */ private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now, - String name, int which, String linePrefix) { + String name, int which, String linePrefix) { long totalTimeMicros = 0; int count = 0; if (timer != null) { - totalTimeMicros = timer.getTotalTime(now, which); - count = timer.getCount(which); + totalTimeMicros = timer.getTotalTimeLocked(now, which); + count = timer.getCountLocked(which); } sb.append(linePrefix); sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding sb.append(','); - sb.append(name); - sb.append(','); + sb.append(name != null ? name + "," : ""); sb.append(count); return ","; } @@ -725,12 +739,12 @@ public abstract class BatteryStats implements Parcelable { Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); if (fullWakeTimer != null) { - fullWakeLockTimeTotal += fullWakeTimer.getTotalTime(batteryRealtime, which); + fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(batteryRealtime, which); } Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); if (partialWakeTimer != null) { - partialWakeLockTimeTotal += partialWakeTimer.getTotalTime( + partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked( batteryRealtime, which); } } @@ -774,8 +788,19 @@ public abstract class BatteryStats implements Parcelable { dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_COUNT_DATA, args); if (which == STATS_UNPLUGGED) { - dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, getUnpluggedStartLevel(), - getPluggedStartLevel()); + dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(), + getDischargeCurrentLevel()); + } + + Map kernelWakelocks = getKernelWakelockStats(); + if (kernelWakelocks.size() > 0) { + for (Map.Entry ent : kernelWakelocks.entrySet()) { + sb.setLength(0); + printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, ""); + + dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), + sb.toString()); + } } for (int iu = 0; iu < NU; iu++) { @@ -816,12 +841,12 @@ public abstract class BatteryStats implements Parcelable { Uid.Wakelock wl = ent.getValue(); String linePrefix = ""; sb.setLength(0); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime, - "full", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime, - "partial", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime, - "window", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), + batteryRealtime, "f", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), + batteryRealtime, "p", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), + batteryRealtime, "w", which, linePrefix); // Only log if we had at lease one wakelock... if (sb.length() > 0) { @@ -839,8 +864,8 @@ public abstract class BatteryStats implements Parcelable { Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000; - int count = timer.getCount(which); + long totalTime = (timer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); if (totalTime != 0) { dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count); } @@ -898,7 +923,7 @@ public abstract class BatteryStats implements Parcelable { } @SuppressWarnings("unused") - private final void dumpLocked(Printer pw, String prefix, int which) { + private final void dumpLocked(PrintWriter pw, String prefix, int which) { final long rawUptime = SystemClock.uptimeMillis() * 1000; final long rawRealtime = SystemClock.elapsedRealtime() * 1000; final long batteryUptime = getBatteryUptime(rawUptime); @@ -914,33 +939,41 @@ public abstract class BatteryStats implements Parcelable { SparseArray uidStats = getUidStats(); final int NU = uidStats.size(); - pw.println(prefix - + " Time on battery: " - + formatTimeMs(whichBatteryRealtime / 1000) + "(" - + formatRatioLocked(whichBatteryRealtime, totalRealtime) - + ") realtime, " - + formatTimeMs(whichBatteryUptime / 1000) - + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime) - + ") uptime"); - pw.println(prefix - + " Total run time: " - + formatTimeMs(totalRealtime / 1000) - + "realtime, " - + formatTimeMs(totalUptime / 1000) - + "uptime, "); + sb.setLength(0); + sb.append(prefix); + sb.append(" Time on battery: "); + formatTimeMs(sb, whichBatteryRealtime / 1000); sb.append("("); + sb.append(formatRatioLocked(whichBatteryRealtime, totalRealtime)); + sb.append(") realtime, "); + formatTimeMs(sb, whichBatteryUptime / 1000); + sb.append("("); sb.append(formatRatioLocked(whichBatteryUptime, totalRealtime)); + sb.append(") uptime"); + pw.println(sb.toString()); + sb.setLength(0); + sb.append(prefix); + sb.append(" Total run time: "); + formatTimeMs(sb, totalRealtime / 1000); + sb.append("realtime, "); + formatTimeMs(sb, totalUptime / 1000); + sb.append("uptime, "); + pw.println(sb.toString()); final long screenOnTime = getScreenOnTime(batteryRealtime, which); final long phoneOnTime = getPhoneOnTime(batteryRealtime, which); final long wifiRunningTime = getWifiRunningTime(batteryRealtime, which); final long wifiOnTime = getWifiOnTime(batteryRealtime, which); final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which); - pw.println(prefix - + " Screen on: " + formatTimeMs(screenOnTime / 1000) - + "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime) - + "), Input events: " + getInputEventCount(which) - + ", Active phone call: " + formatTimeMs(phoneOnTime / 1000) - + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")"); sb.setLength(0); + sb.append(prefix); + sb.append(" Screen on: "); formatTimeMs(sb, screenOnTime / 1000); + sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime)); + sb.append("), Input events: "); sb.append(getInputEventCount(which)); + sb.append(", Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000); + sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime)); + sb.append(")"); + pw.println(sb.toString()); + sb.setLength(0); + sb.append(prefix); sb.append(" Screen brightnesses: "); boolean didOne = false; for (int i=0; i kernelWakelocks = getKernelWakelockStats(); + if (kernelWakelocks.size() > 0) { + for (Map.Entry ent : kernelWakelocks.entrySet()) { + + String linePrefix = ": "; + sb.setLength(0); + sb.append(prefix); + sb.append(" Kernel Wake lock "); + sb.append(ent.getKey()); + linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which, + linePrefix); + if (!linePrefix.equals(": ")) { + sb.append(" realtime"); + } else { + sb.append(": (nothing executed)"); + } + pw.println(sb.toString()); + } + } + for (int iu = 0; iu < NU; iu++) { Uid u = uidStats.valueAt(iu); rxTotal += u.getTcpBytesReceived(which); @@ -979,29 +1032,32 @@ public abstract class BatteryStats implements Parcelable { Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); if (fullWakeTimer != null) { - fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTime( + fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked( batteryRealtime, which); } Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); if (partialWakeTimer != null) { - partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTime( + partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTimeLocked( batteryRealtime, which); } } } } - pw.println(prefix - + " Total received: " + formatBytesLocked(rxTotal) - + ", Total sent: " + formatBytesLocked(txTotal)); - pw.println(prefix - + " Total full wakelock time: " + formatTimeMs( - (fullWakeLockTimeTotalMicros + 500) / 1000) - + ", Total partial waklock time: " + formatTimeMs( - (partialWakeLockTimeTotalMicros + 500) / 1000)); + pw.print(prefix); + pw.print(" Total received: "); pw.print(formatBytesLocked(rxTotal)); + pw.print(", Total sent: "); pw.println(formatBytesLocked(txTotal)); + sb.setLength(0); + sb.append(prefix); + sb.append(" Total full wakelock time: "); formatTimeMs(sb, + (fullWakeLockTimeTotalMicros + 500) / 1000); + sb.append(", Total partial waklock time: "); formatTimeMs(sb, + (partialWakeLockTimeTotalMicros + 500) / 1000); + pw.println(sb.toString()); sb.setLength(0); + sb.append(prefix); sb.append(" Signal levels: "); didOne = false; for (int i=0; i wakelocks = u.getWakelockStats(); @@ -1172,11 +1237,12 @@ public abstract class BatteryStats implements Parcelable { Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000; - int count = timer.getCount(which); + long totalTime = (timer.getTotalTimeLocked( + batteryRealtime, which) + 500) / 1000; + int count = timer.getCountLocked(which); //timer.logState(); if (totalTime != 0) { - sb.append(formatTimeMs(totalTime)); + formatTimeMs(sb, totalTime); sb.append("realtime ("); sb.append(count); sb.append(" times)"); @@ -1206,10 +1272,15 @@ public abstract class BatteryStats implements Parcelable { 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"); + sb.setLength(0); + sb.append(prefix); sb.append(" Proc "); + sb.append(ent.getKey()); sb.append(":\n"); + sb.append(prefix); sb.append(" CPU: "); + formatTime(sb, userTime); sb.append("usr + "); + formatTime(sb, systemTime); sb.append("krn\n"); + sb.append(prefix); sb.append(" "); sb.append(starts); + sb.append(" proc starts"); + pw.println(sb.toString()); uidActivity = true; } } @@ -1219,12 +1290,13 @@ public abstract class BatteryStats implements Parcelable { if (packageStats.size() > 0) { for (Map.Entry ent : packageStats.entrySet()) { - pw.println(prefix + " Apk " + ent.getKey() + ":"); + pw.print(prefix); pw.print(" Apk "); pw.print(ent.getKey()); pw.println(":"); boolean apkActivity = false; Uid.Pkg ps = ent.getValue(); int wakeups = ps.getWakeups(which); if (wakeups != 0) { - pw.println(prefix + " " + wakeups + " wakeup alarms"); + pw.print(prefix); pw.print(" "); + pw.print(wakeups); pw.println(" wakeup alarms"); apkActivity = true; } Map serviceStats = ps.getServiceStats(); @@ -1236,24 +1308,28 @@ public abstract class BatteryStats implements Parcelable { 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 + " Created for: " - + formatTimeMs(startTime / 1000) - + " uptime"); - pw.println(prefix + " Starts: " + starts - + ", launches: " + launches); + sb.setLength(0); + sb.append(prefix); sb.append(" Service "); + sb.append(sent.getKey()); sb.append(":\n"); + sb.append(prefix); sb.append(" Created for: "); + formatTimeMs(sb, startTime / 1000); + sb.append(" uptime\n"); + sb.append(prefix); sb.append(" Starts: "); + sb.append(starts); + sb.append(", launches: "); sb.append(launches); + pw.println(sb.toString()); apkActivity = true; } } } if (!apkActivity) { - pw.println(prefix + " (nothing executed)"); + pw.print(prefix); pw.println(" (nothing executed)"); } uidActivity = true; } } if (!uidActivity) { - pw.println(prefix + " (nothing executed)"); + pw.print(prefix); pw.println(" (nothing executed)"); } } } @@ -1264,7 +1340,7 @@ public abstract class BatteryStats implements Parcelable { * @param pw a Printer to receive the dump output. */ @SuppressWarnings("unused") - public void dumpLocked(Printer pw) { + public void dumpLocked(PrintWriter pw) { pw.println("Total Statistics (Current and Historic):"); pw.println(" System starts: " + getStartCount() + ", currently on battery: " + getIsOnBattery()); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 467c17f7d3a196fd5f408281f6bb5c0b8bafe889..5487c545c12adb6bac35818b8df994f44e25565c 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -59,11 +59,47 @@ public class Build { public static final String RELEASE = getString("ro.build.version.release"); /** - * The user-visible SDK version of the framework. It is an integer starting at 1. + * The user-visible SDK version of the framework in its raw String + * representation; use {@link #SDK_INT} instead. + * + * @deprecated Use {@link #SDK_INT} to easily get this as an integer. */ public static final String SDK = getString("ro.build.version.sdk"); + + /** + * The user-visible SDK version of the framework; its possible + * values are defined in {@link Build.VERSION_CODES}. + */ + public static final int SDK_INT = SystemProperties.getInt( + "ro.build.version.sdk", 0); + + /** + * The current development codename, or the string "REL" if this is + * a release build. + */ + public static final String CODENAME = getString("ro.build.version.codename"); } + /** + * Enumeration of the currently known SDK version codes. These are the + * values that can be found in {@link VERSION#SDK}. Version numbers + * increment monotonically with each official platform release. + */ + public static class VERSION_CODES { + /** + * October 2008: The original, first, version of Android. Yay! + */ + public static final int BASE = 1; + /** + * February 2009: First Android update, officially called 1.1. + */ + public static final int BASE_1_1 = 2; + /** + * May 2009: Android 1.5. + */ + public static final int CUPCAKE = 3; + } + /** The type of build, like "user" or "eng". */ public static final String TYPE = getString("ro.build.type"); diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 950bb09d03c4cf02654673e971a2d81747bb92da..8fcb4d7a40a3054b3a1082ecc5f9a58fd67438ef 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -16,10 +16,24 @@ package android.os; +import com.android.internal.util.TypedProperties; + +import android.util.Config; +import android.util.Log; + +import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.io.Reader; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; @@ -363,6 +377,14 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo VMDebug.startMethodTracing(pathName, bufferSize, flags); } + /** + * Determine whether method tracing is currently active. + * @hide + */ + public static boolean isMethodTracingActive() { + return VMDebug.isMethodTracingActive(); + } + /** * Stop method tracing. */ @@ -713,5 +735,232 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE]; return count; } - }; + } + + + /** + * A Map of typed debug properties. + */ + private static final TypedProperties debugProperties; + + /* + * Load the debug properties from the standard files into debugProperties. + */ + static { + if (Config.DEBUG) { + final String TAG = "DebugProperties"; + final String[] files = { "/system/debug.prop", "/debug.prop", "/data/debug.prop" }; + final TypedProperties tp = new TypedProperties(); + + // Read the properties from each of the files, if present. + for (String file : files) { + Reader r; + try { + r = new FileReader(file); + } catch (FileNotFoundException ex) { + // It's ok if a file is missing. + continue; + } + + try { + tp.load(r); + } catch (Exception ex) { + throw new RuntimeException("Problem loading " + file, ex); + } finally { + try { + r.close(); + } catch (IOException ex) { + // Ignore this error. + } + } + } + + debugProperties = tp.isEmpty() ? null : tp; + } else { + debugProperties = null; + } + } + + + /** + * Returns true if the type of the field matches the specified class. + * Handles the case where the class is, e.g., java.lang.Boolean, but + * the field is of the primitive "boolean" type. Also handles all of + * the java.lang.Number subclasses. + */ + private static boolean fieldTypeMatches(Field field, Class cl) { + Class fieldClass = field.getType(); + if (fieldClass == cl) { + return true; + } + Field primitiveTypeField; + try { + /* All of the classes we care about (Boolean, Integer, etc.) + * have a Class field called "TYPE" that points to the corresponding + * primitive class. + */ + primitiveTypeField = cl.getField("TYPE"); + } catch (NoSuchFieldException ex) { + return false; + } + try { + return fieldClass == (Class) primitiveTypeField.get(null); + } catch (IllegalAccessException ex) { + return false; + } + } + + + /** + * Looks up the property that corresponds to the field, and sets the field's value + * if the types match. + */ + private static void modifyFieldIfSet(final Field field, final TypedProperties properties, + final String propertyName) { + if (field.getType() == java.lang.String.class) { + int stringInfo = properties.getStringInfo(propertyName); + switch (stringInfo) { + case TypedProperties.STRING_SET: + // Handle as usual below. + break; + case TypedProperties.STRING_NULL: + try { + field.set(null, null); // null object for static fields; null string + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException( + "Cannot set field for " + propertyName, ex); + } + return; + case TypedProperties.STRING_NOT_SET: + return; + case TypedProperties.STRING_TYPE_MISMATCH: + throw new IllegalArgumentException( + "Type of " + propertyName + " " + + " does not match field type (" + field.getType() + ")"); + default: + throw new IllegalStateException( + "Unexpected getStringInfo(" + propertyName + ") return value " + + stringInfo); + } + } + Object value = properties.get(propertyName); + if (value != null) { + if (!fieldTypeMatches(field, value.getClass())) { + throw new IllegalArgumentException( + "Type of " + propertyName + " (" + value.getClass() + ") " + + " does not match field type (" + field.getType() + ")"); + } + try { + field.set(null, value); // null object for static fields + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException( + "Cannot set field for " + propertyName, ex); + } + } + } + + + /** + * Equivalent to setFieldsOn(cl, false). + * + * @see #setFieldsOn(Class, boolean) + * + * @hide + */ + public static void setFieldsOn(Class cl) { + setFieldsOn(cl, false); + } + + /** + * Reflectively sets static fields of a class based on internal debugging + * properties. This method is a no-op if android.util.Config.DEBUG is + * false. + *

    + * NOTE TO APPLICATION DEVELOPERS: Config.DEBUG will + * always be false in release builds. This API is typically only useful + * for platform developers. + *

    + * Class setup: define a class whose only fields are non-final, static + * primitive types (except for "char") or Strings. In a static block + * after the field definitions/initializations, pass the class to + * this method, Debug.setFieldsOn(). Example: + *
    +     * package com.example;
    +     *
    +     * import android.os.Debug;
    +     *
    +     * public class MyDebugVars {
    +     *    public static String s = "a string";
    +     *    public static String s2 = "second string";
    +     *    public static String ns = null;
    +     *    public static boolean b = false;
    +     *    public static int i = 5;
    +     *    @Debug.DebugProperty
    +     *    public static float f = 0.1f;
    +     *    @@Debug.DebugProperty
    +     *    public static double d = 0.5d;
    +     *
    +     *    // This MUST appear AFTER all fields are defined and initialized!
    +     *    static {
    +     *        // Sets all the fields
    +     *        Debug.setFieldsOn(MyDebugVars.class);
    +     * 
    +     *        // Sets only the fields annotated with @Debug.DebugProperty
    +     *        // Debug.setFieldsOn(MyDebugVars.class, true);
    +     *    }
    +     * }
    +     * 
    + * setFieldsOn() may override the value of any field in the class based + * on internal properties that are fixed at boot time. + *

    + * These properties are only set during platform debugging, and are not + * meant to be used as a general-purpose properties store. + * + * {@hide} + * + * @param cl The class to (possibly) modify + * @param partial If false, sets all static fields, otherwise, only set + * fields with the {@link android.os.Debug.DebugProperty} + * annotation + * @throws IllegalArgumentException if any fields are final or non-static, + * or if the type of the field does not match the type of + * the internal debugging property value. + */ + public static void setFieldsOn(Class cl, boolean partial) { + if (Config.DEBUG) { + if (debugProperties != null) { + /* Only look for fields declared directly by the class, + * so we don't mysteriously change static fields in superclasses. + */ + for (Field field : cl.getDeclaredFields()) { + if (!partial || field.getAnnotation(DebugProperty.class) != null) { + final String propertyName = cl.getName() + "." + field.getName(); + boolean isStatic = Modifier.isStatic(field.getModifiers()); + boolean isFinal = Modifier.isFinal(field.getModifiers()); + + if (!isStatic || isFinal) { + throw new IllegalArgumentException(propertyName + + " must be static and non-final"); + } + modifyFieldIfSet(field, debugProperties, propertyName); + } + } + } + } else { + Log.w("android.os.Debug", + "setFieldsOn(" + (cl == null ? "null" : cl.getName()) + + ") called in non-DEBUG build"); + } + } + + /** + * Annotation to put on fields you want to set with + * {@link Debug#setFieldsOn(Class, boolean)}. + * + * @hide + */ + @Target({ ElementType.FIELD }) + @Retention(RetentionPolicy.RUNTIME) + public @interface DebugProperty { + } } diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java index 47497e547ff1fc609640139326f1efda07cec98a..3679e478126eef19865d1b6a68b692011585c0c3 100644 --- a/core/java/android/os/Power.java +++ b/core/java/android/os/Power.java @@ -80,10 +80,9 @@ public class Power public static native int setLastUserActivityTimeout(long ms); /** - * Turn the device off. - * - * This method is considered deprecated in favor of - * {@link android.policy.ShutdownThread.shutdownAfterDisablingRadio()}. + * Low-level function turn the device off immediately, without trying + * to be clean. Most people should use + * {@link android.internal.app.ShutdownThread} for a clean shutdown. * * @deprecated * @hide diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index cd86fbe70dac1c9873356bf43c2fab25e037699e..30acef9ee7b581606bf7b38e669bb94916f0b198 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -176,6 +176,26 @@ public class Process { */ public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1; + /** + * Default thread group - gets a 'normal' share of the CPU + * @hide + */ + public static final int THREAD_GROUP_DEFAULT = 0; + + /** + * Background non-interactive thread group - All threads in + * this group are scheduled with a reduced share of the CPU. + * @hide + */ + public static final int THREAD_GROUP_BG_NONINTERACTIVE = 1; + + /** + * Foreground 'boost' thread group - All threads in + * this group are scheduled with an increased share of the CPU + * @hide + **/ + public static final int THREAD_GROUP_FG_BOOST = 2; + public static final int SIGNAL_QUIT = 3; public static final int SIGNAL_KILL = 9; public static final int SIGNAL_USR1 = 10; @@ -569,6 +589,21 @@ public class Process { */ public static final native void setThreadPriority(int tid, int priority) throws IllegalArgumentException, SecurityException; + + /** + * Sets the scheduling group for a thread. + * @hide + * @param tid The indentifier of the thread/process to change. + * @param group The target group for this thread/process. + * + * @throws IllegalArgumentException Throws IllegalArgumentException if + * tid does not exist. + * @throws SecurityException Throws SecurityException if your process does + * not have permission to modify the given thread, or to use the given + * priority. + */ + public static final native void setThreadGroup(int tid, int group) + throws IllegalArgumentException, SecurityException; /** * Set the priority of the calling thread, based on Linux priorities. See @@ -680,6 +715,8 @@ public class Process { /** @hide */ public static final int PROC_SPACE_TERM = (int)' '; /** @hide */ + public static final int PROC_TAB_TERM = (int)'\t'; + /** @hide */ public static final int PROC_COMBINE = 0x100; /** @hide */ public static final int PROC_PARENS = 0x200; @@ -693,6 +730,10 @@ public class Process { /** @hide */ public static final native boolean readProcFile(String file, int[] format, String[] outStrings, long[] outLongs, float[] outFloats); + + /** @hide */ + public static final native boolean parseProcLine(byte[] buffer, int startIndex, + int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats); /** * Gets the total Pss value for a given process, in bytes. diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index 63f6dffba87e5b23617b0c0831552f4460273e86..23c0a7bf473c48c2c93f6f4d9f97881a3c1315cd 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -49,24 +49,34 @@ import java.util.HashMap; public class RemoteCallbackList { /*package*/ HashMap mCallbacks = new HashMap(); - private IInterface[] mActiveBroadcast; + private Object[] mActiveBroadcast; private boolean mKilled = false; private final class Callback implements IBinder.DeathRecipient { final E mCallback; + final Object mCookie; - Callback(E callback) { + Callback(E callback, Object cookie) { mCallback = callback; + mCookie = cookie; } public void binderDied() { synchronized (mCallbacks) { mCallbacks.remove(mCallback.asBinder()); } - onCallbackDied(mCallback); + onCallbackDied(mCallback, mCookie); } } + /** + * Simple version of {@link RemoteCallbackList#register(E, Object)} + * that does not take a cookie object. + */ + public boolean register(E callback) { + return register(callback, null); + } + /** * Add a new callback to the list. This callback will remain in the list * until a corresponding call to {@link #unregister} or its hosting process @@ -81,6 +91,8 @@ public class RemoteCallbackList { * Most services will want to check for null before calling this with * an object given from a client, so that clients can't crash the * service with bad data. + * @param cookie Optional additional data to be associated with this + * callback. * * @return Returns true if the callback was successfully added to the list. * Returns false if it was not added, either because {@link #kill} had @@ -90,14 +102,14 @@ public class RemoteCallbackList { * @see #kill * @see #onCallbackDied */ - public boolean register(E callback) { + public boolean register(E callback, Object cookie) { synchronized (mCallbacks) { if (mKilled) { return false; } IBinder binder = callback.asBinder(); try { - Callback cb = new Callback(callback); + Callback cb = new Callback(callback, cookie); binder.linkToDeath(cb, 0); mCallbacks.put(binder, cb); return true; @@ -153,18 +165,29 @@ public class RemoteCallbackList { } } + /** + * Old version of {@link #onCallbackDied(E, Object)} that + * does not provide a cookie. + */ + public void onCallbackDied(E callback) { + } + /** * Called when the process hosting a callback in the list has gone away. - * The default implementation does nothing. + * The default implementation calls {@link #onCallbackDied(E)} + * for backwards compatibility. * * @param callback The callback whose process has died. Note that, since * its process has died, you can not make any calls on to this interface. * You can, however, retrieve its IBinder and compare it with another * IBinder to see if it is the same object. + * @param cookie The cookie object original provided to + * {@link #register(E, Object)}. * * @see #register */ - public void onCallbackDied(E callback) { + public void onCallbackDied(E callback, Object cookie) { + onCallbackDied(callback); } /** @@ -203,13 +226,13 @@ public class RemoteCallbackList { if (N <= 0) { return 0; } - IInterface[] active = mActiveBroadcast; + Object[] active = mActiveBroadcast; if (active == null || active.length < N) { - mActiveBroadcast = active = new IInterface[N]; + mActiveBroadcast = active = new Object[N]; } int i=0; for (Callback cb : mCallbacks.values()) { - active[i++] = cb.mCallback; + active[i++] = cb; } return i; } @@ -237,7 +260,17 @@ public class RemoteCallbackList { * @see #beginBroadcast */ public E getBroadcastItem(int index) { - return (E)mActiveBroadcast[index]; + return ((Callback)mActiveBroadcast[index]).mCallback; + } + + /** + * Retrieve the cookie associated with the item + * returned by {@link #getBroadcastItem(int)}. + * + * @see #getBroadcastItem + */ + public Object getBroadcastCookie(int index) { + return ((Callback)mActiveBroadcast[index]).mCookie; } /** @@ -248,7 +281,7 @@ public class RemoteCallbackList { * @see #beginBroadcast */ public void finishBroadcast() { - IInterface[] active = mActiveBroadcast; + Object[] active = mActiveBroadcast; if (active != null) { final int N = active.length; for (int i=0; i, OnDependencyChangeLis private boolean mPersistent = true; private String mDependencyKey; private Object mDefaultValue; + private boolean mDependencyMet = true; /** * @see #setShouldDisableView(boolean) @@ -594,7 +595,7 @@ public class Preference implements Comparable, OnDependencyChangeLis * @return True if this Preference is enabled, false otherwise. */ public boolean isEnabled() { - return mEnabled; + return mEnabled && mDependencyMet; } /** @@ -1096,7 +1097,14 @@ public class Preference implements Comparable, OnDependencyChangeLis * @param disableDependent Set true to disable this Preference. */ public void onDependencyChanged(Preference dependency, boolean disableDependent) { - setEnabled(!disableDependent); + if (mDependencyMet == disableDependent) { + mDependencyMet = !disableDependent; + + // Enabled state can change dependent preferences' states, so notify + notifyDependencyChange(shouldDisableDependents()); + + notifyChanged(); + } } /** diff --git a/core/java/android/provider/Applications.java b/core/java/android/provider/Applications.java new file mode 100644 index 0000000000000000000000000000000000000000..0b0ce58f6c1534364f6e84e7124d07030dc01a42 --- /dev/null +++ b/core/java/android/provider/Applications.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.provider; + +import android.app.SearchManager; +import android.net.Uri; +import android.widget.SimpleCursorAdapter; + +/** + *

    The Applications provider gives information about installed applications.

    + * + *

    This provider provides the following columns: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * @hide pending API council approval - should be unhidden at the same time as + * {@link SearchManager#SUGGEST_COLUMN_INTENT_COMPONENT} + */ +public class Applications { + private static final String TAG = "Applications"; + + /** + * The content authority for this provider. + * + * @hide + */ + public static final String AUTHORITY = "applications"; + + /** + * The content:// style URL for this provider + * + * @hide + */ + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); + + /** + * no public constructor since this is a utility class + */ + private Applications() {} +} diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java index a87f5fa23a61d03c40bb7f2a216762c487fb54dd..3c23db03ac0af2337a679b781df9fc046bb17ec0 100644 --- a/core/java/android/provider/Checkin.java +++ b/core/java/android/provider/Checkin.java @@ -132,6 +132,7 @@ public final class Checkin { BROWSER_SNAP_CENTER, BROWSER_TEXT_SIZE_CHANGE, BROWSER_ZOOM_OVERVIEW, + CRASHES_REPORTED, CRASHES_TRUNCATED, ELAPSED_REALTIME_SEC, @@ -181,6 +182,9 @@ public final class Checkin { MARKET_REASON_PARSE_MANIFEST_EMPTY, MARKET_REASON_UNKNOWN, MARKET_STALE_INSTALL_ATTEMPT, + PHONE_CDMA_REGISTERED, + PHONE_CDMA_DATA_ATTEMPTED, + PHONE_CDMA_DATA_CONNECTED, } } @@ -347,3 +351,6 @@ public final class Checkin { } } } + + + diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java index cc039686249dc9a34bd3b45da463cb4800dccfe8..c4b29ae440fafd5b5518b97feaa536bbf7831b4a 100644 --- a/core/java/android/provider/Gmail.java +++ b/core/java/android/provider/Gmail.java @@ -38,7 +38,6 @@ import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import android.text.style.CharacterStyle; import android.text.util.Regex; -import android.util.Config; import android.util.Log; import java.io.UnsupportedEncodingException; @@ -61,6 +60,9 @@ import java.util.regex.Pattern; * @hide */ public final class Gmail { + // Set to true to enable extra debugging. + private static final boolean DEBUG = false; + public static final String GMAIL_AUTH_SERVICE = "mail"; // These constants come from google3/java/com/google/caribou/backend/MailLabel.java. public static final String LABEL_SENT = "^f"; @@ -1195,7 +1197,7 @@ public final class Gmail { @Override public void onChange(boolean selfChange) { - if (Config.DEBUG) { + if (DEBUG) { Log.d(TAG, "MailCursor is notifying " + mObservers.size() + " observers"); } for (MailCursorObserver o: mObservers) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c035be2195d52a5902d1bbc17c6a30329b8cbac0..4dd6524fd2c08b0682fcf0e738f3feedf7c01d3c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1280,7 +1280,7 @@ public final class Settings { // Settings moved to Settings.Secure /** - * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED} + * @deprecated Use {@link android.provider.Settings.Secure#ADB_ENABLED} * instead */ @Deprecated @@ -2034,6 +2034,110 @@ public final class Settings { * ConnectivityManager for more info. */ public static final String BACKGROUND_DATA = "background_data"; + + /** + * The CDMA roaming mode 0 = Home Networks, CDMA default + * 1 = Roaming on Affiliated networks + * 2 = Roaming on any networks + * @hide + */ + public static final String CDMA_ROAMING_MODE = "roaming_settings"; + + /** + * The CDMA subscription mode 0 = RUIM/SIM (default) + * 1 = NV + * @hide + */ + public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode"; + + /** + * represents current active phone class + * 1 = GSM-Phone, 0 = CDMA-Phone + * @hide + */ + public static final String CURRENT_ACTIVE_PHONE = "current_active_phone"; + + /** + * The preferred network mode 7 = Global, CDMA default + * 4 = CDMA only + * 3 = GSM/UMTS only + * @hide + */ + public static final String PREFERRED_NETWORK_MODE = + "preferred_network_mode"; + + /** + * CDMA Cell Broadcast SMS + * 0 = CDMA Cell Broadcast SMS disabled + * 1 = CDMA Cell Broadcast SMS enabled + * @hide + */ + public static final String CDMA_CELL_BROADCAST_SMS = + "cdma_cell_broadcast_sms"; + + /** + * The cdma subscription 0 = Subscription from RUIM, when available + * 1 = Subscription from NV + * @hide + */ + public static final String PREFERRED_CDMA_SUBSCRIPTION = + "preferred_cdma_subscription"; + + /** + * Whether the enhanced voice privacy mode is enabled. + * 0 = normal voice privacy + * 1 = enhanced voice privacy + * @hide + */ + public static final String ENHANCED_VOICE_PRIVACY_ENABLED = "enhanced_voice_privacy_enabled"; + + /** + * Whether the TTY mode mode is enabled. + * 0 = disabled + * 1 = enabled + * @hide + */ + public static final String TTY_MODE_ENABLED = "tty_mode_enabled"; + + /** + * Helper method for determining if a location provider is enabled. + * @param cr the content resolver to use + * @param provider the location provider to query + * @return true if the provider is enabled + * + * @hide + */ + public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) { + String allowedProviders = Settings.Secure.getString(cr, LOCATION_PROVIDERS_ALLOWED); + if (allowedProviders != null) { + return (allowedProviders.equals(provider) || + allowedProviders.contains("," + provider + ",") || + allowedProviders.startsWith(provider + ",") || + allowedProviders.endsWith("," + provider)); + } + return false; + } + + /** + * Thread-safe method for enabling or disabling a single location provider. + * @param cr the content resolver to use + * @param provider the location provider to enable or disable + * @param enabled true if the provider should be enabled + * + * @hide + */ + public static final void setLocationProviderEnabled(ContentResolver cr, + String provider, boolean enabled) { + // to ensure thread safety, we write the provider name with a '+' or '-' + // and let the SettingsProvider handle it rather than reading and modifying + // the list of enabled providers. + if (enabled) { + provider = "+" + provider; + } else { + provider = "-" + provider; + } + putString(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider); + } } /** @@ -2323,6 +2427,12 @@ public final class Settings { */ public static final String GMAIL_BUFFER_SERVER_RESPONSE = "gmail_buffer_server_response"; + /** + * Controls whether Gmail will discard uphill operations that repeatedly fail. Value must be + * an integer where non-zero means true. Defaults to 1. + */ + public static final String GMAIL_DISCARD_ERROR_UPHILL_OP = "gmail_discard_error_uphill_op"; + /** * Hostname of the GTalk server. */ @@ -3112,13 +3222,13 @@ public final class Settings { throw new RuntimeException("this should never happen"); } - String imei = TelephonyManager.getDefault().getDeviceId(); - if (TextUtils.isEmpty(imei)) { + String deviceId = TelephonyManager.getDefault().getDeviceId(); + if (TextUtils.isEmpty(deviceId)) { return ""; } - byte[] hashedImei = digest.digest(imei.getBytes()); - String id = new String(Base64.encodeBase64(hashedImei), 0, 12); + byte[] hashedDeviceId = digest.digest(deviceId.getBytes()); + String id = new String(Base64.encodeBase64(hashedDeviceId), 0, 12); id = id.replaceAll("/", "_"); sJidResource = JID_RESOURCE_PREFIX + id; return sJidResource; @@ -3137,3 +3247,4 @@ public final class Settings { return "android-" + Long.toHexString(androidId); } } + diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java deleted file mode 100644 index 628852f4c37cf1fc93e3b89da509d994d59f57a1..0000000000000000000000000000000000000000 --- a/core/java/android/provider/Sync.java +++ /dev/null @@ -1,633 +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 android.provider; - -import android.content.ContentQueryMap; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; -import android.os.Handler; - -import java.util.Map; - -/** - * The Sync provider stores information used in managing the syncing of the device, - * including the history and pending syncs. - * - * @hide - */ -public final class Sync { - // utility class - private Sync() {} - - /** - * The content url for this provider. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync"); - - /** - * Columns from the stats table. - */ - public interface StatsColumns { - /** - * The sync account. - *

    Type: TEXT

    - */ - public static final String ACCOUNT = "account"; - - /** - * The content authority (contacts, calendar, etc.). - *

    Type: TEXT

    - */ - public static final String AUTHORITY = "authority"; - } - - /** - * Provides constants and utility methods to access and use the stats table. - */ - public static final class Stats implements BaseColumns, StatsColumns { - - // utility class - private Stats() {} - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sync/stats"); - - /** Projection for the _id column in the stats table. */ - public static final String[] SYNC_STATS_PROJECTION = {_ID}; - } - - /** - * Columns from the history table. - */ - public interface HistoryColumns { - /** - * The ID of the stats row corresponding to this event. - *

    Type: INTEGER

    - */ - public static final String STATS_ID = "stats_id"; - - /** - * The source of the sync event (LOCAL, POLL, USER, SERVER). - *

    Type: INTEGER

    - */ - public static final String SOURCE = "source"; - - /** - * The type of sync event (START, STOP). - *

    Type: INTEGER

    - */ - public static final String EVENT = "event"; - - /** - * The time of the event. - *

    Type: INTEGER

    - */ - public static final String EVENT_TIME = "eventTime"; - - /** - * How long this event took. This is only valid if the EVENT is EVENT_STOP. - *

    Type: INTEGER

    - */ - public static final String ELAPSED_TIME = "elapsedTime"; - - /** - * Any additional message associated with this event. - *

    Type: TEXT

    - */ - public static final String MESG = "mesg"; - - /** - * How much activity was performed sending data to the server. This is sync adapter - * specific, but usually is something like how many record update/insert/delete attempts - * were carried out. This is only valid if the EVENT is EVENT_STOP. - *

    Type: INTEGER

    - */ - public static final String UPSTREAM_ACTIVITY = "upstreamActivity"; - - /** - * How much activity was performed while receiving data from the server. - * This is sync adapter specific, but usually is something like how many - * records were received from the server. This is only valid if the - * EVENT is EVENT_STOP. - *

    Type: INTEGER

    - */ - public static final String DOWNSTREAM_ACTIVITY = "downstreamActivity"; - } - - /** - * Columns from the history table. - */ - public interface StatusColumns { - /** - * How many syncs were completed for this account and authority. - *

    Type: INTEGER

    - */ - public static final String NUM_SYNCS = "numSyncs"; - - /** - * How long all the events for this account and authority took. - *

    Type: INTEGER

    - */ - public static final String TOTAL_ELAPSED_TIME = "totalElapsedTime"; - - /** - * The number of syncs with SOURCE_POLL. - *

    Type: INTEGER

    - */ - public static final String NUM_SOURCE_POLL = "numSourcePoll"; - - /** - * The number of syncs with SOURCE_SERVER. - *

    Type: INTEGER

    - */ - public static final String NUM_SOURCE_SERVER = "numSourceServer"; - - /** - * The number of syncs with SOURCE_LOCAL. - *

    Type: INTEGER

    - */ - public static final String NUM_SOURCE_LOCAL = "numSourceLocal"; - - /** - * The number of syncs with SOURCE_USER. - *

    Type: INTEGER

    - */ - public static final String NUM_SOURCE_USER = "numSourceUser"; - - /** - * The time in ms that the last successful sync ended. Will be null if - * there are no successful syncs. A successful sync is defined as one having - * MESG=MESG_SUCCESS. - *

    Type: INTEGER

    - */ - public static final String LAST_SUCCESS_TIME = "lastSuccessTime"; - - /** - * The SOURCE of the last successful sync. Will be null if - * there are no successful syncs. A successful sync is defined - * as one having MESG=MESG_SUCCESS. - *

    Type: INTEGER

    - */ - public static final String LAST_SUCCESS_SOURCE = "lastSuccessSource"; - - /** - * The end time in ms of the last sync that failed since the last successful sync. - * Will be null if there are no syncs or if the last one succeeded. A failed - * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED. - *

    Type: INTEGER

    - */ - public static final String LAST_FAILURE_TIME = "lastFailureTime"; - - /** - * The SOURCE of the last sync that failed since the last successful sync. - * Will be null if there are no syncs or if the last one succeeded. A failed - * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED. - *

    Type: INTEGER

    - */ - public static final String LAST_FAILURE_SOURCE = "lastFailureSource"; - - /** - * The MESG of the last sync that failed since the last successful sync. - * Will be null if there are no syncs or if the last one succeeded. A failed - * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED. - *

    Type: STRING

    - */ - public static final String LAST_FAILURE_MESG = "lastFailureMesg"; - - /** - * Is set to 1 if a sync is pending, 0 if not. - *

    Type: INTEGER

    - */ - public static final String PENDING = "pending"; - } - - /** - * Provides constants and utility methods to access and use the history - * table. - */ - public static class History implements BaseColumns, - StatsColumns, - HistoryColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sync/history"); - - /** Enum value for a sync start event. */ - public static final int EVENT_START = 0; - - /** Enum value for a sync stop event. */ - public static final int EVENT_STOP = 1; - - // TODO: i18n -- grab these out of resources. - /** String names for the sync event types. */ - public static final String[] EVENTS = { "START", "STOP" }; - - /** Enum value for a server-initiated sync. */ - public static final int SOURCE_SERVER = 0; - - /** Enum value for a local-initiated sync. */ - public static final int SOURCE_LOCAL = 1; - /** - * Enum value for a poll-based sync (e.g., upon connection to - * network) - */ - public static final int SOURCE_POLL = 2; - - /** Enum value for a user-initiated sync. */ - public static final int SOURCE_USER = 3; - - // TODO: i18n -- grab these out of resources. - /** String names for the sync source types. */ - public static final String[] SOURCES = { "SERVER", - "LOCAL", - "POLL", - "USER" }; - - // Error types - public static final int ERROR_SYNC_ALREADY_IN_PROGRESS = 1; - public static final int ERROR_AUTHENTICATION = 2; - public static final int ERROR_IO = 3; - public static final int ERROR_PARSE = 4; - public static final int ERROR_CONFLICT = 5; - public static final int ERROR_TOO_MANY_DELETIONS = 6; - public static final int ERROR_TOO_MANY_RETRIES = 7; - public static final int ERROR_INTERNAL = 8; - - // The MESG column will contain one of these or one of the Error types. - public static final String MESG_SUCCESS = "success"; - public static final String MESG_CANCELED = "canceled"; - - private static final String FINISHED_SINCE_WHERE_CLAUSE = EVENT + "=" + EVENT_STOP - + " AND " + EVENT_TIME + ">? AND " + ACCOUNT + "=? AND " + AUTHORITY + "=?"; - - public static String mesgToString(String mesg) { - if (MESG_SUCCESS.equals(mesg)) return mesg; - if (MESG_CANCELED.equals(mesg)) return mesg; - switch (Integer.parseInt(mesg)) { - case ERROR_SYNC_ALREADY_IN_PROGRESS: return "already in progress"; - case ERROR_AUTHENTICATION: return "bad authentication"; - case ERROR_IO: return "network error"; - case ERROR_PARSE: return "parse error"; - case ERROR_CONFLICT: return "conflict detected"; - case ERROR_TOO_MANY_DELETIONS: return "too many deletions"; - case ERROR_TOO_MANY_RETRIES: return "too many retries"; - case ERROR_INTERNAL: return "internal error"; - default: return "unknown error"; - } - } - - // utility class - private History() {} - - /** - * returns a cursor that queries the sync history in descending event time order - * @param contentResolver the ContentResolver to use for the query - * @return the cursor on the History table - */ - public static Cursor query(ContentResolver contentResolver) { - return contentResolver.query(CONTENT_URI, null, null, null, EVENT_TIME + " desc"); - } - - public static boolean hasNewerSyncFinished(ContentResolver contentResolver, - String account, String authority, long when) { - Cursor c = contentResolver.query(CONTENT_URI, new String[]{_ID}, - FINISHED_SINCE_WHERE_CLAUSE, - new String[]{Long.toString(when), account, authority}, null); - try { - return c.getCount() > 0; - } finally { - c.close(); - } - } - } - - /** - * Provides constants and utility methods to access and use the authority history - * table, which contains information about syncs aggregated by account and authority. - * All the HistoryColumns except for EVENT are present, plus the AuthorityHistoryColumns. - */ - public static class Status extends History implements StatusColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/status"); - - // utility class - private Status() {} - - /** - * returns a cursor that queries the authority sync history in descending event order of - * ACCOUNT, AUTHORITY - * @param contentResolver the ContentResolver to use for the query - * @return the cursor on the AuthorityHistory table - */ - public static Cursor query(ContentResolver contentResolver) { - return contentResolver.query(CONTENT_URI, null, null, null, ACCOUNT + ", " + AUTHORITY); - } - - public static class QueryMap extends ContentQueryMap { - public QueryMap(ContentResolver contentResolver, - boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), - _ID, keepUpdated, handlerForUpdateNotifications); - } - - public ContentValues get(String account, String authority) { - Map rows = getRows(); - for (ContentValues values : rows.values()) { - if (values.getAsString(ACCOUNT).equals(account) - && values.getAsString(AUTHORITY).equals(authority)) { - return values; - } - } - return null; - } - } - } - - /** - * Provides constants and utility methods to access and use the pending syncs table - */ - public static final class Pending implements BaseColumns, - StatsColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/pending"); - - // utility class - private Pending() {} - - public static class QueryMap extends ContentQueryMap { - public QueryMap(ContentResolver contentResolver, boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), _ID, keepUpdated, - handlerForUpdateNotifications); - } - - public boolean isPending(String account, String authority) { - Map rows = getRows(); - for (ContentValues values : rows.values()) { - if (values.getAsString(ACCOUNT).equals(account) - && values.getAsString(AUTHORITY).equals(authority)) { - return true; - } - } - return false; - } - } - } - - /** - * Columns from the history table. - */ - public interface ActiveColumns { - /** - * The wallclock time of when the active sync started. - *

    Type: INTEGER

    - */ - public static final String START_TIME = "startTime"; - } - - /** - * Provides constants and utility methods to access and use the pending syncs table - */ - public static final class Active implements BaseColumns, - StatsColumns, - ActiveColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/active"); - - // utility class - private Active() {} - - public static class QueryMap extends ContentQueryMap { - public QueryMap(ContentResolver contentResolver, boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), _ID, keepUpdated, - handlerForUpdateNotifications); - } - - public ContentValues getActiveSyncInfo() { - Map rows = getRows(); - for (ContentValues values : rows.values()) { - return values; - } - return null; - } - - public String getSyncingAccount() { - ContentValues values = getActiveSyncInfo(); - return (values == null) ? null : values.getAsString(ACCOUNT); - } - - public String getSyncingAuthority() { - ContentValues values = getActiveSyncInfo(); - return (values == null) ? null : values.getAsString(AUTHORITY); - } - - public long getSyncStartTime() { - ContentValues values = getActiveSyncInfo(); - return (values == null) ? -1 : values.getAsLong(START_TIME); - } - } - } - - /** - * Columns in the settings table, which holds key/value pairs of settings. - */ - public interface SettingsColumns { - /** - * The key of the setting - *

    Type: TEXT

    - */ - public static final String KEY = "name"; - - /** - * The value of the settings - *

    Type: TEXT

    - */ - public static final String VALUE = "value"; - } - - /** - * Provides constants and utility methods to access and use the settings - * table. - */ - public static final class Settings implements BaseColumns, SettingsColumns { - /** - * The Uri of the settings table. This table behaves a little differently than - * normal tables. Updates are not allowed, only inserts, and inserts cause a replace - * to be performed, which first deletes the row if it is already present. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/settings"); - - /** 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 individual provider is synced when tickles are received */ - public static final String SETTING_SYNC_PROVIDER_PREFIX = "sync_provider_"; - - /** query column project */ - private static final String[] PROJECTION = { KEY, VALUE }; - - /** - * Convenience function for updating a single settings value as a - * boolean. 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 contentResolver the ContentResolver to use to access the settings table - * @param name The name of the setting to modify. - * @param val The new value for the setting. - */ - static private void putBoolean(ContentResolver contentResolver, String name, boolean val) { - ContentValues values = new ContentValues(); - values.put(KEY, name); - values.put(VALUE, Boolean.toString(val)); - // this insert is translated into an update by the underlying Sync provider - contentResolver.insert(CONTENT_URI, values); - } - - /** - * Convenience function for getting a setting value as a boolean without using the - * QueryMap for light-weight setting querying. - * @param contentResolver The ContentResolver for querying the setting. - * @param name The name of the setting to query - * @param def The default value for the setting. - * @return The value of the setting. - */ - static public boolean getBoolean(ContentResolver contentResolver, - String name, boolean def) { - Cursor cursor = contentResolver.query( - CONTENT_URI, - PROJECTION, - KEY + "=?", - new String[] { name }, - null); - try { - if (cursor != null && cursor.moveToFirst()) { - return Boolean.parseBoolean(cursor.getString(1)); - } - } finally { - if (cursor != null) cursor.close(); - } - return def; - } - - /** - * A convenience method to set whether or not the provider is synced when - * it receives a network tickle. - * - * @param contentResolver the ContentResolver to use to access the settings table - * @param providerName the provider whose behavior is being controlled - * @param sync true if the provider should be synced when tickles are received for it - */ - static public void setSyncProviderAutomatically(ContentResolver contentResolver, - String providerName, boolean sync) { - putBoolean(contentResolver, SETTING_SYNC_PROVIDER_PREFIX + providerName, sync); - } - - /** - * 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 it should listen. - */ - static public void setListenForNetworkTickles(ContentResolver contentResolver, - boolean flag) { - putBoolean(contentResolver, SETTING_LISTEN_FOR_TICKLES, flag); - } - - public static class QueryMap extends ContentQueryMap { - private ContentResolver mContentResolver; - - public QueryMap(ContentResolver contentResolver, boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), KEY, keepUpdated, - handlerForUpdateNotifications); - mContentResolver = contentResolver; - } - - /** - * Check if the provider should be synced when a network tickle is received - * @param providerName the provider whose setting we are querying - * @return true of the provider should be synced when a network tickle is received - */ - public boolean getSyncProviderAutomatically(String providerName) { - return getBoolean(SETTING_SYNC_PROVIDER_PREFIX + providerName, true); - } - - /** - * Set whether or not the provider is synced when it receives a network tickle. - * - * @param providerName the provider whose behavior is being controlled - * @param sync true if the provider should be synced when tickles are received for it - */ - public void setSyncProviderAutomatically(String providerName, boolean sync) { - Settings.setSyncProviderAutomatically(mContentResolver, providerName, sync); - } - - /** - * Set whether or not the device should listen for tickles. - * - * @param flag true if it should listen. - */ - public void setListenForNetworkTickles(boolean flag) { - Settings.setListenForNetworkTickles(mContentResolver, flag); - } - - /** - * Check if the device should listen to tickles. - - * @return true if it should - */ - public boolean getListenForNetworkTickles() { - return getBoolean(SETTING_LISTEN_FOR_TICKLES, true); - } - - /** - * Convenience function for retrieving a single settings value - * as a boolean. - * - * @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. - */ - private boolean getBoolean(String name, boolean def) { - ContentValues values = getValues(name); - return values != null ? values.getAsBoolean(VALUE) : def; - } - } - } -} diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 61ab2288cb6f83a448db177958656d08ca5c2a10..a4145c487696b0267dcf35e8ae1f94c8cc862acb 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -26,7 +26,7 @@ import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import android.telephony.gsm.SmsMessage; +import android.telephony.SmsMessage; import android.text.TextUtils; import android.text.util.Regex; import android.util.Config; @@ -47,6 +47,10 @@ public final class Telephony { private static final boolean DEBUG = false; private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; + // Constructor + public Telephony() { + } + /** * Base columns for tables that contain text based SMSs. */ @@ -1601,3 +1605,5 @@ public final class Telephony { } + + diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 11c297cb99e4dcae0a990fb0a8f8fed475f1c5af..8cc229bf7dfc09911acc069c913b5f39cfdbbbc1 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -111,57 +111,27 @@ class BluetoothEventLoop { return mPasskeyAgentRequestData; } - private synchronized boolean waitForAndDispatchEvent(int timeout_ms) { - return waitForAndDispatchEventNative(timeout_ms); - } - private native boolean waitForAndDispatchEventNative(int timeout_ms); + private native void startEventLoopNative(); + private native void stopEventLoopNative(); + private native boolean isEventLoopRunningNative(); - /* package */ synchronized void start() { + /* package */ void start() { - if (mThread != null) { - // Already running. - return; + if (!isEventLoopRunningNative()) { + if (DBG) log("Starting Event Loop thread"); + startEventLoopNative(); } - mThread = new Thread("Bluetooth Event Loop") { - @Override - public void run() { - try { - if (setUpEventLoopNative()) { - mStarted = true; - while (!mInterrupted) { - waitForAndDispatchEvent(0); - sleep(500); - } - } - // tear down even in the error case to clean - // up anything we started to setup - tearDownEventLoopNative(); - } catch (InterruptedException e) { } - if (DBG) log("Event Loop thread finished"); - mThread = null; - } - }; - if (DBG) log("Starting Event Loop thread"); - mInterrupted = false; - mThread.start(); } - private native boolean setUpEventLoopNative(); - private native void tearDownEventLoopNative(); - public synchronized void stop() { - if (mThread != null) { - mInterrupted = true; - try { - mThread.join(); - mThread = null; - } catch (InterruptedException e) { - Log.i(TAG, "Interrupted waiting for Event Loop thread to join"); - } + public void stop() { + if (isEventLoopRunningNative()) { + if (DBG) log("Stopping Event Loop thread"); + stopEventLoopNative(); } } - public synchronized boolean isEventLoopRunning() { - return mThread != null && mStarted; + public boolean isEventLoopRunning() { + return isEventLoopRunningNative(); } /*package*/ void onModeChanged(String bluezMode) { diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java index fe155536ba549e9d7bf8aeaf795187cb268fbb1a..03623d6bf411307d3e56e687504dbbeafcc3b02a 100644 --- a/core/java/android/server/search/SearchManagerService.java +++ b/core/java/android/server/search/SearchManagerService.java @@ -23,7 +23,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; -import android.util.Config; + +import java.util.List; /** * This is a simplified version of the Search Manager service. It no longer handles @@ -36,7 +37,6 @@ public class SearchManagerService extends ISearchManager.Stub // general debugging support private static final String TAG = "SearchManagerService"; private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; // configuration choices private static final boolean IMMEDIATE_SEARCHABLES_UPDATE = true; @@ -45,9 +45,10 @@ public class SearchManagerService extends ISearchManager.Stub private final Context mContext; private final Handler mHandler; private boolean mSearchablesDirty; + private Searchables mSearchables; /** - * Initialize the Search Manager service in the provided system context. + * Initializes the Search Manager service in the provided system context. * Only one instance of this object should be created! * * @param context to use for accessing DB, window manager, etc. @@ -55,6 +56,8 @@ public class SearchManagerService extends ISearchManager.Stub public SearchManagerService(Context context) { mContext = context; mHandler = new Handler(); + mSearchablesDirty = true; + mSearchables = new Searchables(context); // Setup the infrastructure for updating and maintaining the list // of searchable activities. @@ -64,7 +67,6 @@ public class SearchManagerService extends ISearchManager.Stub filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); - mSearchablesDirty = true; // After startup settles down, preload the searchables list, // which will reduce the delay when the search UI is invoked. @@ -109,34 +111,24 @@ public class SearchManagerService extends ISearchManager.Stub }; /** - * Update the list of searchables, either at startup or in response to + * Updates the list of searchables, either at startup or in response to * a package add/remove broadcast message. */ private void updateSearchables() { - SearchableInfo.buildSearchableList(mContext); + mSearchables.buildSearchableList(); mSearchablesDirty = false; - - // TODO This is a hack. This shouldn't be hardcoded here, it's probably - // a policy. -// ComponentName defaultSearch = new ComponentName( -// "com.android.contacts", -// "com.android.contacts.ContactsListActivity" ); - ComponentName defaultSearch = new ComponentName( - "com.android.googlesearch", - "com.android.googlesearch.GoogleSearch" ); - SearchableInfo.setDefaultSearchable(mContext, defaultSearch); } /** - * Return the searchableinfo for a given activity + * Returns the SearchableInfo for a given activity * * @param launchActivity The activity from which we're launching this search. - * @return Returns a SearchableInfo record describing the parameters of the search, - * or null if no searchable metadata was available. * @param globalSearch If false, this will only launch the search that has been specifically * defined by the application (which is usually defined as a local search). If no default * search is defined in the current application or activity, no search will be launched. * If true, this will always launch a platform-global (e.g. web-based) search instead. + * @return Returns a SearchableInfo record describing the parameters of the search, + * or null if no searchable metadata was available. */ public SearchableInfo getSearchableInfo(ComponentName launchActivity, boolean globalSearch) { // final check. however we should try to avoid this, because @@ -146,11 +138,19 @@ public class SearchManagerService extends ISearchManager.Stub } SearchableInfo si = null; if (globalSearch) { - si = SearchableInfo.getDefaultSearchable(); + si = mSearchables.getDefaultSearchable(); } else { - si = SearchableInfo.getSearchableInfo(mContext, launchActivity); + si = mSearchables.getSearchableInfo(launchActivity); } return si; } + + /** + * Returns a list of the searchable activities that can be included in global search. + */ + public List getSearchablesInGlobalSearch() { + return mSearchables.getSearchablesInGlobalSearchList(); + } + } diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java index 0c04839a4472b7d169d6d76411e1221e728f38de..842fc7573aefdf145809010867e9df347634b775 100644 --- a/core/java/android/server/search/SearchableInfo.java +++ b/core/java/android/server/search/SearchableInfo.java @@ -21,14 +21,11 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.text.InputType; @@ -38,96 +35,60 @@ import android.util.Xml; import android.view.inputmethod.EditorInfo; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; public final class SearchableInfo implements Parcelable { // general debugging support - final static String LOG_TAG = "SearchableInfo"; - - // set this flag to 1 to prevent any apps from providing suggestions - final static int DBG_INHIBIT_SUGGESTIONS = 0; + private static final boolean DBG = true; + private static final String LOG_TAG = "SearchableInfo"; - // static strings used for XML lookups, etc. + // static strings used for XML lookups. // TODO how should these be documented for the developer, in a more structured way than // the current long wordy javadoc in SearchManager.java ? - private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable"; private static final String MD_LABEL_SEARCHABLE = "android.app.searchable"; - private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*"; private static final String MD_XML_ELEMENT_SEARCHABLE = "searchable"; private static final String MD_XML_ELEMENT_SEARCHABLE_ACTION_KEY = "actionkey"; - - // class maintenance and general shared data - private static HashMap sSearchablesMap = null; - private static ArrayList sSearchablesList = null; - private static SearchableInfo sDefaultSearchable = null; + + // flags in the searchMode attribute + private static final int SEARCH_MODE_BADGE_LABEL = 0x04; + private static final int SEARCH_MODE_BADGE_ICON = 0x08; + private static final int SEARCH_MODE_QUERY_REWRITE_FROM_DATA = 0x10; + private static final int SEARCH_MODE_QUERY_REWRITE_FROM_TEXT = 0x20; // true member variables - what we know about the searchability - // TO-DO replace public with getters - public boolean mSearchable = false; - private int mLabelId = 0; - public ComponentName mSearchActivity = null; - private int mHintId = 0; - private int mSearchMode = 0; - public boolean mBadgeLabel = false; - public boolean mBadgeIcon = false; - public boolean mQueryRewriteFromData = false; - public boolean mQueryRewriteFromText = false; - private int mIconId = 0; - private int mSearchButtonText = 0; - private int mSearchInputType = 0; - private int mSearchImeOptions = 0; - private String mSuggestAuthority = null; - private String mSuggestPath = null; - private String mSuggestSelection = null; - private String mSuggestIntentAction = null; - private String mSuggestIntentData = null; - private ActionKeyInfo mActionKeyList = null; - private String mSuggestProviderPackage = null; - private Context mCacheActivityContext = null; // use during setup only - don't hold memory! + private final int mLabelId; + private final ComponentName mSearchActivity; + private final int mHintId; + private final int mSearchMode; + private final int mIconId; + private final int mSearchButtonText; + private final int mSearchInputType; + private final int mSearchImeOptions; + private final boolean mIncludeInGlobalSearch; + private final String mSuggestAuthority; + private final String mSuggestPath; + private final String mSuggestSelection; + private final String mSuggestIntentAction; + private final String mSuggestIntentData; + private final int mSuggestThreshold; + // Maps key codes to action key information. auto-boxing is not so bad here, + // since keycodes for the hard keys are < 127. For such values, Integer.valueOf() + // uses shared Integer objects. + // This is not final, to allow lazy initialization. + private HashMap mActionKeys = null; + private final String mSuggestProviderPackage; // Flag values for Searchable_voiceSearchMode private static int VOICE_SEARCH_SHOW_BUTTON = 1; private static int VOICE_SEARCH_LAUNCH_WEB_SEARCH = 2; private static int VOICE_SEARCH_LAUNCH_RECOGNIZER = 4; - private int mVoiceSearchMode = 0; - private int mVoiceLanguageModeId; // voiceLanguageModel - private int mVoicePromptTextId; // voicePromptText - private int mVoiceLanguageId; // voiceLanguage - private int mVoiceMaxResults; // voiceMaxResults - - /** - * Set the default searchable activity (when none is specified). - */ - public static void setDefaultSearchable(Context context, - ComponentName activity) { - synchronized (SearchableInfo.class) { - SearchableInfo si = null; - if (activity != null) { - si = getSearchableInfo(context, activity); - if (si != null) { - // move to front of list - sSearchablesList.remove(si); - sSearchablesList.add(0, si); - } - } - sDefaultSearchable = si; - } - } - - /** - * Provides the system-default search activity, which you can use - * whenever getSearchableInfo() returns null; - * - * @return Returns the system-default search activity, null if never defined - */ - public static SearchableInfo getDefaultSearchable() { - synchronized (SearchableInfo.class) { - return sDefaultSearchable; - } - } + private final int mVoiceSearchMode; + private final int mVoiceLanguageModeId; // voiceLanguageModel + private final int mVoicePromptTextId; // voicePromptText + private final int mVoiceLanguageId; // voiceLanguage + private final int mVoiceMaxResults; // voiceMaxResults + /** * Retrieve the authority for obtaining search suggestions. @@ -137,7 +98,42 @@ public final class SearchableInfo implements Parcelable { public String getSuggestAuthority() { return mSuggestAuthority; } - + + /** + * Gets the component name of the searchable activity. + */ + public ComponentName getSearchActivity() { + return mSearchActivity; + } + + /** + * Checks whether the badge should be a text label. + */ + public boolean useBadgeLabel() { + return 0 != (mSearchMode & SEARCH_MODE_BADGE_LABEL); + } + + /** + * Checks whether the badge should be an icon. + */ + public boolean useBadgeIcon() { + return (0 != (mSearchMode & SEARCH_MODE_BADGE_ICON)) && (mIconId != 0); + } + + /** + * Checks whether the text in the query field should come from the suggestion intent data. + */ + public boolean shouldRewriteQueryFromData() { + return 0 != (mSearchMode & SEARCH_MODE_QUERY_REWRITE_FROM_DATA); + } + + /** + * Checks whether the text in the query field should come from the suggestion title. + */ + public boolean shouldRewriteQueryFromText() { + return 0 != (mSearchMode & SEARCH_MODE_QUERY_REWRITE_FROM_TEXT); + } + /** * Retrieve the path for obtaining search suggestions. * @@ -183,6 +179,16 @@ public final class SearchableInfo implements Parcelable { return mSuggestIntentData; } + /** + * Gets the suggestion threshold for use with these suggestions. + * + * @return The value of the searchSuggestThreshold attribute, + * or 0 if the attribute is not set. + */ + public int getSuggestThreshold() { + return mSuggestThreshold; + } + /** * Get the context for the searchable activity. * @@ -193,9 +199,16 @@ public final class SearchableInfo implements Parcelable { * @return Returns a context related to the searchable activity */ public Context getActivityContext(Context context) { + return createActivityContext(context, mSearchActivity); + } + + /** + * Creates a context for another activity. + */ + private static Context createActivityContext(Context context, ComponentName activity) { Context theirContext = null; try { - theirContext = context.createPackageContext(mSearchActivity.getPackageName(), 0); + theirContext = context.createPackageContext(activity.getPackageName(), 0); } catch (PackageManager.NameNotFoundException e) { // unexpected, but we deal with this by null-checking theirContext } catch (java.lang.SecurityException e) { @@ -233,310 +246,121 @@ public final class SearchableInfo implements Parcelable { return theirContext; } - /** - * Factory. Look up, or construct, based on the activity. - * - * The activities fall into three cases, based on meta-data found in - * the manifest entry: - *
      - *
    1. The activity itself implements search. This is indicated by the - * presence of a "android.app.searchable" meta-data attribute. - * The value is a reference to an XML file containing search information.
    2. - *
    3. A related activity implements search. This is indicated by the - * presence of a "android.app.default_searchable" meta-data attribute. - * The value is a string naming the activity implementing search. In this - * case the factory will "redirect" and return the searchable data.
    4. - *
    5. No searchability data is provided. We return null here and other - * code will insert the "default" (e.g. contacts) search. - * - * TODO: cache the result in the map, and check the map first. - * TODO: it might make sense to implement the searchable reference as - * an application meta-data entry. This way we don't have to pepper each - * and every activity. - * TODO: can we skip the constructor step if it's a non-searchable? - * TODO: does it make sense to plug the default into a slot here for - * automatic return? Probably not, but it's one way to do it. - * - * @param activity The name of the current activity, or null if the - * activity does not define any explicit searchable metadata. - */ - public static SearchableInfo getSearchableInfo(Context context, - ComponentName activity) { - // Step 1. Is the result already hashed? (case 1) - SearchableInfo result; - synchronized (SearchableInfo.class) { - result = sSearchablesMap.get(activity); - if (result != null) return result; - } - - // Step 2. See if the current activity references a searchable. - // Note: Conceptually, this could be a while(true) loop, but there's - // no point in implementing reference chaining here and risking a loop. - // References must point directly to searchable activities. - - ActivityInfo ai = null; - XmlPullParser xml = null; - try { - ai = context.getPackageManager(). - getActivityInfo(activity, PackageManager.GET_META_DATA ); - String refActivityName = null; - - // First look for activity-specific reference - Bundle md = ai.metaData; - if (md != null) { - refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); - } - // If not found, try for app-wide reference - if (refActivityName == null) { - md = ai.applicationInfo.metaData; - if (md != null) { - refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); - } - } - - // Irrespective of source, if a reference was found, follow it. - if (refActivityName != null) - { - // An app or activity can declare that we should simply launch - // "system default search" if search is invoked. - if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) { - return getDefaultSearchable(); - } - String pkg = activity.getPackageName(); - ComponentName referredActivity; - if (refActivityName.charAt(0) == '.') { - referredActivity = new ComponentName(pkg, pkg + refActivityName); - } else { - referredActivity = new ComponentName(pkg, refActivityName); - } - - // Now try the referred activity, and if found, cache - // it against the original name so we can skip the check - synchronized (SearchableInfo.class) { - result = sSearchablesMap.get(referredActivity); - if (result != null) { - sSearchablesMap.put(activity, result); - return result; - } - } - } - } catch (PackageManager.NameNotFoundException e) { - // case 3: no metadata - } - - // Step 3. None found. Return null. - return null; - - } - - /** - * Super-factory. Builds an entire list (suitable for display) of - * activities that are searchable, by iterating the entire set of - * ACTION_SEARCH intents. - * - * Also clears the hash of all activities -> searches which will - * refill as the user clicks "search". - * - * This should only be done at startup and again if we know that the - * list has changed. - * - * TODO: every activity that provides a ACTION_SEARCH intent should - * also provide searchability meta-data. There are a bunch of checks here - * that, if data is not found, silently skip to the next activity. This - * won't help a developer trying to figure out why their activity isn't - * showing up in the list, but an exception here is too rough. I would - * like to find a better notification mechanism. - * - * TODO: sort the list somehow? UI choice. - * - * @param context a context we can use during this work - */ - public static void buildSearchableList(Context context) { - - // create empty hash & list - HashMap newSearchablesMap - = new HashMap(); - ArrayList newSearchablesList - = new ArrayList(); - - // use intent resolver to generate list of ACTION_SEARCH receivers - final PackageManager pm = context.getPackageManager(); - List infoList; - final Intent intent = new Intent(Intent.ACTION_SEARCH); - infoList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); - - // analyze each one, generate a Searchables record, and record - if (infoList != null) { - int count = infoList.size(); - for (int ii = 0; ii < count; ii++) { - // for each component, try to find metadata - ResolveInfo info = infoList.get(ii); - ActivityInfo ai = info.activityInfo; - XmlResourceParser xml = ai.loadXmlMetaData(context.getPackageManager(), - MD_LABEL_SEARCHABLE); - if (xml == null) { - continue; - } - ComponentName cName = new ComponentName( - info.activityInfo.packageName, - info.activityInfo.name); - - SearchableInfo searchable = getActivityMetaData(context, xml, cName); - xml.close(); - - if (searchable != null) { - // no need to keep the context any longer. setup time is over. - searchable.mCacheActivityContext = null; - - newSearchablesList.add(searchable); - newSearchablesMap.put(cName, searchable); - } - } - } - - // record the final values as a coherent pair - synchronized (SearchableInfo.class) { - sSearchablesList = newSearchablesList; - sSearchablesMap = newSearchablesMap; - } - } - /** * Constructor * * Given a ComponentName, get the searchability info * and build a local copy of it. Use the factory, not this. * - * @param context runtime context + * @param activityContext runtime context for the activity that the searchable info is about. * @param attr The attribute set we found in the XML file, contains the values that are used to * construct the object. * @param cName The component name of the searchable activity + * @throws IllegalArgumentException if the searchability info is invalid or insufficient */ - private SearchableInfo(Context context, AttributeSet attr, final ComponentName cName) { - // initialize as an "unsearchable" object - mSearchable = false; + private SearchableInfo(Context activityContext, AttributeSet attr, final ComponentName cName) { 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); - if (mCacheActivityContext != null) { - TypedArray a = mCacheActivityContext.obtainStyledAttributes(attr, - com.android.internal.R.styleable.Searchable); - mSearchMode = a.getInt(com.android.internal.R.styleable.Searchable_searchMode, 0); - mLabelId = a.getResourceId(com.android.internal.R.styleable.Searchable_label, 0); - mHintId = a.getResourceId(com.android.internal.R.styleable.Searchable_hint, 0); - mIconId = a.getResourceId(com.android.internal.R.styleable.Searchable_icon, 0); - mSearchButtonText = a.getResourceId( - com.android.internal.R.styleable.Searchable_searchButtonText, 0); - mSearchInputType = a.getInt(com.android.internal.R.styleable.Searchable_inputType, - InputType.TYPE_CLASS_TEXT | - InputType.TYPE_TEXT_VARIATION_NORMAL); - mSearchImeOptions = a.getInt(com.android.internal.R.styleable.Searchable_imeOptions, - EditorInfo.IME_ACTION_SEARCH); - - setSearchModeFlags(); - if (DBG_INHIBIT_SUGGESTIONS == 0) { - mSuggestAuthority = a.getString( - com.android.internal.R.styleable.Searchable_searchSuggestAuthority); - mSuggestPath = a.getString( - com.android.internal.R.styleable.Searchable_searchSuggestPath); - mSuggestSelection = a.getString( - com.android.internal.R.styleable.Searchable_searchSuggestSelection); - mSuggestIntentAction = a.getString( - com.android.internal.R.styleable.Searchable_searchSuggestIntentAction); - mSuggestIntentData = a.getString( - com.android.internal.R.styleable.Searchable_searchSuggestIntentData); - } - mVoiceSearchMode = - a.getInt(com.android.internal.R.styleable.Searchable_voiceSearchMode, 0); - // TODO this didn't work - came back zero from YouTube - mVoiceLanguageModeId = - a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguageModel, 0); - mVoicePromptTextId = - a.getResourceId(com.android.internal.R.styleable.Searchable_voicePromptText, 0); - mVoiceLanguageId = - a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguage, 0); - mVoiceMaxResults = - a.getInt(com.android.internal.R.styleable.Searchable_voiceMaxResults, 0); + TypedArray a = activityContext.obtainStyledAttributes(attr, + com.android.internal.R.styleable.Searchable); + mSearchMode = a.getInt(com.android.internal.R.styleable.Searchable_searchMode, 0); + mLabelId = a.getResourceId(com.android.internal.R.styleable.Searchable_label, 0); + mHintId = a.getResourceId(com.android.internal.R.styleable.Searchable_hint, 0); + mIconId = a.getResourceId(com.android.internal.R.styleable.Searchable_icon, 0); + mSearchButtonText = a.getResourceId( + com.android.internal.R.styleable.Searchable_searchButtonText, 0); + mSearchInputType = a.getInt(com.android.internal.R.styleable.Searchable_inputType, + InputType.TYPE_CLASS_TEXT | + InputType.TYPE_TEXT_VARIATION_NORMAL); + mSearchImeOptions = a.getInt(com.android.internal.R.styleable.Searchable_imeOptions, + EditorInfo.IME_ACTION_SEARCH); + mIncludeInGlobalSearch = a.getBoolean( + com.android.internal.R.styleable.Searchable_includeInGlobalSearch, false); - a.recycle(); + mSuggestAuthority = a.getString( + com.android.internal.R.styleable.Searchable_searchSuggestAuthority); + mSuggestPath = a.getString( + com.android.internal.R.styleable.Searchable_searchSuggestPath); + mSuggestSelection = a.getString( + com.android.internal.R.styleable.Searchable_searchSuggestSelection); + mSuggestIntentAction = a.getString( + com.android.internal.R.styleable.Searchable_searchSuggestIntentAction); + mSuggestIntentData = a.getString( + com.android.internal.R.styleable.Searchable_searchSuggestIntentData); + mSuggestThreshold = a.getInt( + com.android.internal.R.styleable.Searchable_searchSuggestThreshold, 0); - // get package info for suggestions provider (if any) - if (mSuggestAuthority != null) { - ProviderInfo pi = - context.getPackageManager().resolveContentProvider(mSuggestAuthority, - 0); - if (pi != null) { - mSuggestProviderPackage = pi.packageName; - } + mVoiceSearchMode = + a.getInt(com.android.internal.R.styleable.Searchable_voiceSearchMode, 0); + // TODO this didn't work - came back zero from YouTube + mVoiceLanguageModeId = + a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguageModel, 0); + mVoicePromptTextId = + a.getResourceId(com.android.internal.R.styleable.Searchable_voicePromptText, 0); + mVoiceLanguageId = + a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguage, 0); + mVoiceMaxResults = + a.getInt(com.android.internal.R.styleable.Searchable_voiceMaxResults, 0); + + a.recycle(); + + // get package info for suggestions provider (if any) + String suggestProviderPackage = null; + if (mSuggestAuthority != null) { + PackageManager pm = activityContext.getPackageManager(); + ProviderInfo pi = pm.resolveContentProvider(mSuggestAuthority, 0); + if (pi != null) { + suggestProviderPackage = pi.packageName; } } + mSuggestProviderPackage = suggestProviderPackage; // for now, implement some form of rules - minimal data - if (mLabelId != 0) { - mSearchable = true; - } else { - // Provide some help for developers instead of just silently discarding - Log.w(LOG_TAG, "Insufficient metadata to configure searchability for " + - cName.flattenToShortString()); + if (mLabelId == 0) { + throw new IllegalArgumentException("No label."); } } - - /** - * Convert searchmode to flags. - */ - private void setSearchModeFlags() { - mBadgeLabel = (0 != (mSearchMode & 4)); - mBadgeIcon = (0 != (mSearchMode & 8)) && (mIconId != 0); - mQueryRewriteFromData = (0 != (mSearchMode & 0x10)); - mQueryRewriteFromText = (0 != (mSearchMode & 0x20)); - } /** * Private class used to hold the "action key" configuration */ - public class ActionKeyInfo implements Parcelable { + public static class ActionKeyInfo implements Parcelable { - public int mKeyCode = 0; - public String mQueryActionMsg; - public String mSuggestActionMsg; - public String mSuggestActionMsgColumn; - private ActionKeyInfo mNext; + private final int mKeyCode; + private final String mQueryActionMsg; + private final String mSuggestActionMsg; + private final String mSuggestActionMsgColumn; /** * Create one object using attributeset as input data. - * @param context runtime context + * @param activityContext runtime context of the activity that the action key information + * is about. * @param attr The attribute set we found in the XML file, contains the values that are used to * construct the object. - * @param next We'll build these up using a simple linked list (since there are usually - * just zero or one). + * @throws IllegalArgumentException if the action key configuration is invalid */ - public ActionKeyInfo(Context context, AttributeSet attr, ActionKeyInfo next) { - TypedArray a = mCacheActivityContext.obtainStyledAttributes(attr, + public ActionKeyInfo(Context activityContext, AttributeSet attr) { + TypedArray a = activityContext.obtainStyledAttributes(attr, com.android.internal.R.styleable.SearchableActionKey); mKeyCode = a.getInt( com.android.internal.R.styleable.SearchableActionKey_keycode, 0); mQueryActionMsg = a.getString( com.android.internal.R.styleable.SearchableActionKey_queryActionMsg); - if (DBG_INHIBIT_SUGGESTIONS == 0) { - mSuggestActionMsg = a.getString( - com.android.internal.R.styleable.SearchableActionKey_suggestActionMsg); - mSuggestActionMsgColumn = a.getString( - com.android.internal.R.styleable.SearchableActionKey_suggestActionMsgColumn); - } + mSuggestActionMsg = a.getString( + com.android.internal.R.styleable.SearchableActionKey_suggestActionMsg); + mSuggestActionMsgColumn = a.getString( + com.android.internal.R.styleable.SearchableActionKey_suggestActionMsgColumn); a.recycle(); - // initialize any other fields - mNext = next; - - // sanity check. must have at least one action message, or invalidate the object. - if ((mQueryActionMsg == null) && + // sanity check. + if (mKeyCode == 0) { + throw new IllegalArgumentException("No keycode."); + } else if ((mQueryActionMsg == null) && (mSuggestActionMsg == null) && (mSuggestActionMsgColumn == null)) { - mKeyCode = 0; - } + throw new IllegalArgumentException("No message information."); + } } /** @@ -545,14 +369,28 @@ public final class SearchableInfo implements Parcelable { * * @param in The Parcel containing the previously written ActionKeyInfo, * positioned at the location in the buffer where it was written. - * @param next The value to place in mNext, creating a linked list */ - public ActionKeyInfo(Parcel in, ActionKeyInfo next) { + public ActionKeyInfo(Parcel in) { mKeyCode = in.readInt(); mQueryActionMsg = in.readString(); mSuggestActionMsg = in.readString(); mSuggestActionMsgColumn = in.readString(); - mNext = next; + } + + public int getKeyCode() { + return mKeyCode; + } + + public String getQueryActionMsg() { + return mQueryActionMsg; + } + + public String getSuggestActionMsg() { + return mSuggestActionMsg; + } + + public String getSuggestActionMsgColumn() { + return mSuggestActionMsgColumn; } public int describeContents() { @@ -574,21 +412,46 @@ public final class SearchableInfo implements Parcelable { * @return Returns the ActionKeyInfo record, or null if none defined */ public ActionKeyInfo findActionKey(int keyCode) { - ActionKeyInfo info = mActionKeyList; - while (info != null) { - if (info.mKeyCode == keyCode) { - return info; - } - info = info.mNext; + if (mActionKeys == null) { + return null; + } + return mActionKeys.get(keyCode); + } + + private void addActionKey(ActionKeyInfo keyInfo) { + if (mActionKeys == null) { + mActionKeys = new HashMap(); + } + mActionKeys.put(keyInfo.getKeyCode(), keyInfo); + } + + public static SearchableInfo getActivityMetaData(Context context, ActivityInfo activityInfo) { + // for each component, try to find metadata + XmlResourceParser xml = + activityInfo.loadXmlMetaData(context.getPackageManager(), MD_LABEL_SEARCHABLE); + if (xml == null) { + return null; + } + ComponentName cName = new ComponentName(activityInfo.packageName, activityInfo.name); + + SearchableInfo searchable = getActivityMetaData(context, xml, cName); + xml.close(); + + if (DBG) { + Log.d(LOG_TAG, "Checked " + activityInfo.name + + ",label=" + searchable.getLabelId() + + ",icon=" + searchable.getIconId() + + ",suggestAuthority=" + searchable.getSuggestAuthority() + + ",target=" + searchable.getSearchActivity().getClassName() + + ",global=" + searchable.shouldIncludeInGlobalSearch() + + ",threshold=" + searchable.getSuggestThreshold()); } - return null; + return searchable; } /** * Get the metadata for a given activity * - * TODO: clean up where we return null vs. where we throw exceptions. - * * @param context runtime context * @param xml XML parser for reading attributes * @param cName The component name of the searchable activity @@ -598,6 +461,7 @@ public final class SearchableInfo implements Parcelable { private static SearchableInfo getActivityMetaData(Context context, XmlPullParser xml, final ComponentName cName) { SearchableInfo result = null; + Context activityContext = createActivityContext(context, cName); // in order to use the attributes mechanism, we have to walk the parser // forward through the file until it's reading the tag of interest. @@ -608,9 +472,11 @@ public final class SearchableInfo implements Parcelable { if (xml.getName().equals(MD_XML_ELEMENT_SEARCHABLE)) { AttributeSet attr = Xml.asAttributeSet(xml); if (attr != null) { - result = new SearchableInfo(context, attr, cName); - // if the constructor returned a bad object, exit now. - if (! result.mSearchable) { + try { + result = new SearchableInfo(activityContext, attr, cName); + } catch (IllegalArgumentException ex) { + Log.w(LOG_TAG, "Invalid searchable metadata for " + + cName.flattenToShortString() + ": " + ex.getMessage()); return null; } } @@ -621,11 +487,12 @@ public final class SearchableInfo implements Parcelable { } AttributeSet attr = Xml.asAttributeSet(xml); if (attr != null) { - ActionKeyInfo keyInfo = result.new ActionKeyInfo(context, attr, - result.mActionKeyList); - // only add to list if it is was useable - if (keyInfo.mKeyCode != 0) { - result.mActionKeyList = keyInfo; + try { + result.addActionKey(new ActionKeyInfo(activityContext, attr)); + } catch (IllegalArgumentException ex) { + Log.w(LOG_TAG, "Invalid action key for " + + cName.flattenToShortString() + ": " + ex.getMessage()); + return null; } } } @@ -633,13 +500,16 @@ public final class SearchableInfo implements Parcelable { tagType = xml.next(); } } catch (XmlPullParserException e) { - throw new RuntimeException(e); + Log.w(LOG_TAG, "Reading searchable metadata for " + cName.flattenToShortString(), e); + return null; } catch (IOException e) { - throw new RuntimeException(e); + Log.w(LOG_TAG, "Reading searchable metadata for " + cName.flattenToShortString(), e); + return null; } + return result; } - + /** * Return the "label" (user-visible name) of this searchable context. This must be * accessed using the target (searchable) Activity's resources, not simply the context of the @@ -757,15 +627,15 @@ public final class SearchableInfo implements Parcelable { } /** - * Return the list of searchable activities, for use in the drop-down. + * Checks whether the searchable is exported. + * + * @return The value of the exported attribute, + * or false if the attribute is not set. */ - public static ArrayList getSearchablesList() { - synchronized (SearchableInfo.class) { - ArrayList result = new ArrayList(sSearchablesList); - return result; - } + public boolean shouldIncludeInGlobalSearch() { + return mIncludeInGlobalSearch; } - + /** * Support for parcelable and aidl operations. */ @@ -788,7 +658,6 @@ public final class SearchableInfo implements Parcelable { * positioned at the location in the buffer where it was written. */ public SearchableInfo(Parcel in) { - mSearchable = in.readInt() != 0; mLabelId = in.readInt(); mSearchActivity = ComponentName.readFromParcel(in); mHintId = in.readInt(); @@ -797,20 +666,19 @@ public final class SearchableInfo implements Parcelable { mSearchButtonText = in.readInt(); mSearchInputType = in.readInt(); mSearchImeOptions = in.readInt(); - setSearchModeFlags(); + mIncludeInGlobalSearch = in.readInt() != 0; mSuggestAuthority = in.readString(); mSuggestPath = in.readString(); mSuggestSelection = in.readString(); mSuggestIntentAction = in.readString(); mSuggestIntentData = in.readString(); + mSuggestThreshold = in.readInt(); - mActionKeyList = null; - int count = in.readInt(); - while (count-- > 0) { - mActionKeyList = new ActionKeyInfo(in, mActionKeyList); + for (int count = in.readInt(); count > 0; count--) { + addActionKey(new ActionKeyInfo(in)); } - + mSuggestProviderPackage = in.readString(); mVoiceSearchMode = in.readInt(); @@ -825,7 +693,6 @@ public final class SearchableInfo implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mSearchable ? 1 : 0); dest.writeInt(mLabelId); mSearchActivity.writeToParcel(dest, flags); dest.writeInt(mHintId); @@ -834,27 +701,24 @@ public final class SearchableInfo implements Parcelable { dest.writeInt(mSearchButtonText); dest.writeInt(mSearchInputType); dest.writeInt(mSearchImeOptions); + dest.writeInt(mIncludeInGlobalSearch ? 1 : 0); dest.writeString(mSuggestAuthority); dest.writeString(mSuggestPath); dest.writeString(mSuggestSelection); dest.writeString(mSuggestIntentAction); dest.writeString(mSuggestIntentData); + dest.writeInt(mSuggestThreshold); - // This is usually a very short linked list so we'll just pre-count it - ActionKeyInfo nextKeyInfo = mActionKeyList; - int count = 0; - while (nextKeyInfo != null) { - ++count; - nextKeyInfo = nextKeyInfo.mNext; - } - dest.writeInt(count); - // Now write count of 'em - nextKeyInfo = mActionKeyList; - while (count-- > 0) { - nextKeyInfo.writeToParcel(dest, flags); + if (mActionKeys == null) { + dest.writeInt(0); + } else { + dest.writeInt(mActionKeys.size()); + for (ActionKeyInfo actionKey : mActionKeys.values()) { + actionKey.writeToParcel(dest, flags); + } } - + dest.writeString(mSuggestProviderPackage); dest.writeInt(mVoiceSearchMode); diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java new file mode 100644 index 0000000000000000000000000000000000000000..9586d56e8e8d6811c9234eb151da9833e4736c09 --- /dev/null +++ b/core/java/android/server/search/Searchables.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.server.search; + +import android.app.SearchManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * This class maintains the information about all searchable activities. + */ +public class Searchables { + + // static strings used for XML lookups, etc. + // TODO how should these be documented for the developer, in a more structured way than + // the current long wordy javadoc in SearchManager.java ? + private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable"; + private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*"; + + private Context mContext; + + private HashMap mSearchablesMap = null; + private ArrayList mSearchablesList = null; + private ArrayList mSearchablesInGlobalSearchList = null; + private SearchableInfo mDefaultSearchable = null; + + /** + * + * @param context Context to use for looking up activities etc. + */ + public Searchables (Context context) { + mContext = context; + } + + /** + * Look up, or construct, based on the activity. + * + * The activities fall into three cases, based on meta-data found in + * the manifest entry: + *
        + *
      1. The activity itself implements search. This is indicated by the + * presence of a "android.app.searchable" meta-data attribute. + * The value is a reference to an XML file containing search information.
      2. + *
      3. A related activity implements search. This is indicated by the + * presence of a "android.app.default_searchable" meta-data attribute. + * The value is a string naming the activity implementing search. In this + * case the factory will "redirect" and return the searchable data.
      4. + *
      5. No searchability data is provided. We return null here and other + * code will insert the "default" (e.g. contacts) search. + * + * TODO: cache the result in the map, and check the map first. + * TODO: it might make sense to implement the searchable reference as + * an application meta-data entry. This way we don't have to pepper each + * and every activity. + * TODO: can we skip the constructor step if it's a non-searchable? + * TODO: does it make sense to plug the default into a slot here for + * automatic return? Probably not, but it's one way to do it. + * + * @param activity The name of the current activity, or null if the + * activity does not define any explicit searchable metadata. + */ + public SearchableInfo getSearchableInfo(ComponentName activity) { + // Step 1. Is the result already hashed? (case 1) + SearchableInfo result; + synchronized (this) { + result = mSearchablesMap.get(activity); + if (result != null) return result; + } + + // Step 2. See if the current activity references a searchable. + // Note: Conceptually, this could be a while(true) loop, but there's + // no point in implementing reference chaining here and risking a loop. + // References must point directly to searchable activities. + + ActivityInfo ai = null; + try { + ai = mContext.getPackageManager(). + getActivityInfo(activity, PackageManager.GET_META_DATA ); + String refActivityName = null; + + // First look for activity-specific reference + Bundle md = ai.metaData; + if (md != null) { + refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); + } + // If not found, try for app-wide reference + if (refActivityName == null) { + md = ai.applicationInfo.metaData; + if (md != null) { + refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); + } + } + + // Irrespective of source, if a reference was found, follow it. + if (refActivityName != null) + { + // An app or activity can declare that we should simply launch + // "system default search" if search is invoked. + if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) { + return getDefaultSearchable(); + } + String pkg = activity.getPackageName(); + ComponentName referredActivity; + if (refActivityName.charAt(0) == '.') { + referredActivity = new ComponentName(pkg, pkg + refActivityName); + } else { + referredActivity = new ComponentName(pkg, refActivityName); + } + + // Now try the referred activity, and if found, cache + // it against the original name so we can skip the check + synchronized (this) { + result = mSearchablesMap.get(referredActivity); + if (result != null) { + mSearchablesMap.put(activity, result); + return result; + } + } + } + } catch (PackageManager.NameNotFoundException e) { + // case 3: no metadata + } + + // Step 3. None found. Return null. + return null; + + } + + /** + * Provides the system-default search activity, which you can use + * whenever getSearchableInfo() returns null; + * + * @return Returns the system-default search activity, null if never defined + */ + public synchronized SearchableInfo getDefaultSearchable() { + return mDefaultSearchable; + } + + public synchronized boolean isDefaultSearchable(SearchableInfo searchable) { + return searchable == mDefaultSearchable; + } + + /** + * Builds an entire list (suitable for display) of + * activities that are searchable, by iterating the entire set of + * ACTION_SEARCH intents. + * + * Also clears the hash of all activities -> searches which will + * refill as the user clicks "search". + * + * This should only be done at startup and again if we know that the + * list has changed. + * + * TODO: every activity that provides a ACTION_SEARCH intent should + * also provide searchability meta-data. There are a bunch of checks here + * that, if data is not found, silently skip to the next activity. This + * won't help a developer trying to figure out why their activity isn't + * showing up in the list, but an exception here is too rough. I would + * like to find a better notification mechanism. + * + * TODO: sort the list somehow? UI choice. + */ + public void buildSearchableList() { + + // These will become the new values at the end of the method + HashMap newSearchablesMap + = new HashMap(); + ArrayList newSearchablesList + = new ArrayList(); + ArrayList newSearchablesInGlobalSearchList + = new ArrayList(); + + final PackageManager pm = mContext.getPackageManager(); + + // use intent resolver to generate list of ACTION_SEARCH receivers + List infoList; + final Intent intent = new Intent(Intent.ACTION_SEARCH); + infoList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); + + // analyze each one, generate a Searchables record, and record + if (infoList != null) { + int count = infoList.size(); + for (int ii = 0; ii < count; ii++) { + // for each component, try to find metadata + ResolveInfo info = infoList.get(ii); + ActivityInfo ai = info.activityInfo; + SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai); + if (searchable != null) { + newSearchablesList.add(searchable); + newSearchablesMap.put(searchable.getSearchActivity(), searchable); + if (searchable.shouldIncludeInGlobalSearch()) { + newSearchablesInGlobalSearchList.add(searchable); + } + } + } + } + + // Find the global search provider + Intent globalSearchIntent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH); + ComponentName globalSearchActivity = globalSearchIntent.resolveActivity(pm); + SearchableInfo newDefaultSearchable = newSearchablesMap.get(globalSearchActivity); + + // Store a consistent set of new values + synchronized (this) { + mSearchablesMap = newSearchablesMap; + mSearchablesList = newSearchablesList; + mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList; + mDefaultSearchable = newDefaultSearchable; + } + } + + /** + * Returns the list of searchable activities. + */ + public synchronized ArrayList getSearchablesList() { + ArrayList result = new ArrayList(mSearchablesList); + return result; + } + + /** + * Returns a list of the searchable activities that can be included in global search. + */ + public synchronized ArrayList getSearchablesInGlobalSearchList() { + return new ArrayList(mSearchablesInGlobalSearchList); + } +} diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl new file mode 100644 index 0000000000000000000000000000000000000000..6ed32b502b424084e48e6d7101ae223c7e16623d --- /dev/null +++ b/core/java/android/speech/IRecognitionListener.aidl @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.speech; + +import android.os.Bundle; + +/** + * Listener for speech recognition events, used with RecognitionService. + * This gives you both the final recognition results, as well as various + * intermediate events that can be used to show visual feedback to the user. + * {@hide} + */ +interface IRecognitionListener { + /** Called when the endpointer is ready for the user to start speaking. */ + void onReadyForSpeech(in Bundle noiseParams); + + /** The user has started to speak. */ + void onBeginningOfSpeech(); + + /** The sound level in the audio stream has changed. */ + void onRmsChanged(in float rmsdB); + + /** + * More sound has been received. Buffer is a byte buffer containing + * a sequence of 16-bit shorts. + */ + void onBufferReceived(in byte[] buffer); + + /** Called after the user stops speaking. */ + void onEndOfSpeech(); + + /** A network or recognition error occurred. */ + void onError(in String error); + + /** + * Called when recognition transcripts are ready. + * results: an ordered list of the most likely transcripts (N-best list). + * @hide + */ + void onResults(in List results); +} diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl new file mode 100644 index 0000000000000000000000000000000000000000..36d12e9aae6437c01d39def2956ab737c28c399d --- /dev/null +++ b/core/java/android/speech/IRecognitionService.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.speech; + +import android.content.Intent; +import android.speech.IRecognitionListener; + +// A Service interface to speech recognition. Call startListening when +// you want to begin capturing audio; RecognitionService will automatically +// determine when the user has finished speaking, stream the audio to the +// recognition servers, and notify you when results are ready. +/** {@hide} */ +interface IRecognitionService { + // Start listening for speech. Can only call this from one thread at once. + // see RecognizerIntent.java for constants used to specify the intent. + void startListening(in Intent recognizerIntent, + in IRecognitionListener listener); + + void cancel(); +} diff --git a/core/java/android/speech/RecognitionServiceUtil.java b/core/java/android/speech/RecognitionServiceUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..650c0fd2488179922fae54ef9b71d32db6eecb93 --- /dev/null +++ b/core/java/android/speech/RecognitionServiceUtil.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 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.speech; + +import android.content.ComponentName; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; + +import java.util.List; + +/** + * Utils for Google's network-based speech recognizer, which lets you perform + * speech-to-text translation through RecognitionService. IRecognitionService + * and IRecognitionListener are the core interfaces; you begin recognition + * through IRecognitionService and subscribe to callbacks about when the user + * stopped speaking, results come in, errors, etc. through IRecognitionListener. + * RecognitionServiceUtil includes default IRecognitionListener and + * ServiceConnection implementations to reduce the amount of boilerplate. + * + * The Service provides no user interface. See RecognitionActivity if you + * want the standard voice search UI. + * + * Below is a small skeleton of how to use the recognizer: + * + * ServiceConnection conn = new RecognitionServiceUtil.Connection(); + * mContext.bindService(RecognitionServiceUtil.sDefaultIntent, + * conn, Context.BIND_AUTO_CREATE); + * IRecognitionListener listener = new RecognitionServiceWrapper.NullListener() { + * public void onResults(List results) { + * // Do something with recognition transcripts + * } + * } + * + * // Must wait for conn.mService to be populated, then call below + * conn.mService.startListening(null, listener); + * + * {@hide} + */ +public class RecognitionServiceUtil { + public static final Intent sDefaultIntent = new Intent( + RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + + public static final String NOISE_LEVEL = "NoiseLevel"; + public static final String SIGNAL_NOISE_RATIO = "SignalNoiseRatio"; + + private RecognitionServiceUtil() {} + + /** + * IRecognitionListener which does nothing in response to recognition + * callbacks. You can subclass from this and override only the methods + * whose events you want to respond to. + */ + public static class NullListener extends IRecognitionListener.Stub { + public void onReadyForSpeech(Bundle bundle) {} + public void onBeginningOfSpeech() {} + public void onRmsChanged(float rmsdB) {} + public void onBufferReceived(byte[] buf) {} + public void onEndOfSpeech() {} + public void onError(String error) {} + public void onResults(List results) {} + } + + /** + * Basic ServiceConnection which just records mService variable. + */ + public static class Connection implements ServiceConnection { + public IRecognitionService mService; + + public synchronized void onServiceConnected(ComponentName name, IBinder service) { + mService = IRecognitionService.Stub.asInterface(service); + } + + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + } +} diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java index 82f2ef9dd8ebb84d8c5dcc8befb90410415aa8ec..470ab0d9a48e67bd54a2ba138b449faffc18f93f 100644 --- a/core/java/android/test/InstrumentationTestCase.java +++ b/core/java/android/test/InstrumentationTestCase.java @@ -62,6 +62,10 @@ public class InstrumentationTestCase extends TestCase { * action = {@link Intent#ACTION_MAIN} * extras = null, unless a custom bundle is provided here * All other fields are null or empty. + * + *

        NOTE: The parameter pkg must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. * * @param pkg The package hosting the activity to be launched. * @param activityCls The activity class to launch. @@ -82,6 +86,11 @@ public class InstrumentationTestCase extends TestCase { /** * Utility method for launching an activity with a specific Intent. + * + *

        NOTE: The parameter pkg must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * * @param pkg The package hosting the activity to be launched. * @param activityCls The activity class to launch. * @param intent The intent to launch with diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index a6ed922f89febbf848c372aaa6589f49a9c54640..29dc2ea5246e200baa13f734cdb2fc0d38c664e1 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -24,7 +24,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Path; import com.android.internal.util.ArrayUtils; -import android.util.Config; import junit.framework.Assert; import android.text.style.*; @@ -39,6 +38,8 @@ import android.view.KeyEvent; * For text that will not change, use a {@link StaticLayout}. */ public abstract class Layout { + private static final boolean DEBUG = false; + /* package */ static final EmojiFactory EMOJI_FACTORY = EmojiFactory.newAvailableInstance(); /* package */ static final int MIN_EMOJI, MAX_EMOJI; @@ -330,7 +331,7 @@ public abstract class Layout { boolean hasTab = getLineContainsTab(i); if (directions == DIRS_ALL_LEFT_TO_RIGHT && !spannedText && !hasTab) { - if (Config.DEBUG) { + if (DEBUG) { Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT); Assert.assertNotNull(c); } @@ -797,7 +798,7 @@ public abstract class Layout { } private int getLineVisibleEnd(int line, int start, int end) { - if (Config.DEBUG) { + if (DEBUG) { Assert.assertTrue(getLineStart(line) == start && getLineStart(line+1) == end); } @@ -1340,7 +1341,7 @@ public abstract class Layout { char[] buf; if (!hasTabs) { if (directions == DIRS_ALL_LEFT_TO_RIGHT) { - if (Config.DEBUG) { + if (DEBUG) { Assert.assertTrue(DIR_LEFT_TO_RIGHT == dir); } Styled.drawText(canvas, text, start, end, dir, false, x, top, y, bottom, paint, workPaint, false); diff --git a/core/java/android/util/CharsetUtils.java b/core/java/android/util/CharsetUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..75530296d2d9397d34e0c65226df36f647accb1d --- /dev/null +++ b/core/java/android/util/CharsetUtils.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import android.os.Build; + +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; + +/** + * A class containing utility methods related to character sets. This + * class is primarily useful for code that wishes to be vendor-aware + * in its interpretation of Japanese encoding names. + * + *

        As of this writing, the only vendor that is recognized by this + * class is Docomo (identified case-insensitively as {@code "docomo"}).

        + * + * Note: This class is hidden in Cupcake, with a plan to + * un-hide in Donut. This was done because the first deployment to use + * this code is based on Cupcake, but the API had to be introduced + * after the public API freeze for that release. The upshot is that + * only system applications can safely use this class until Donut is + * available. + * + * @hide + */ +public final class CharsetUtils { + /** + * name of the vendor "Docomo". Note: This isn't a public + * constant, in order to keep this class from becoming a de facto + * reference list of vendor names. + */ + private static final String VENDOR_DOCOMO = "docomo"; + + /** + * This class is uninstantiable. + */ + private CharsetUtils() { + // This space intentionally left blank. + } + + /** + * Returns the name of the vendor-specific character set + * corresponding to the given original character set name and + * vendor. If there is no vendor-specific character set for the + * given name/vendor pair, this returns the original character set + * name. The vendor name is matched case-insensitively. + * + * @param charsetName the base character set name + * @param vendor the vendor to specialize for + * @return the specialized character set name, or {@code charsetName} if + * there is no specialized name + */ + public static String nameForVendor(String charsetName, String vendor) { + // TODO: Eventually, this may want to be table-driven. + + if (vendor.equalsIgnoreCase(VENDOR_DOCOMO) + && isShiftJis(charsetName)) { + return "docomo-shift_jis-2007"; + } + + return charsetName; + } + + /** + * Returns the name of the vendor-specific character set + * corresponding to the given original character set name and the + * default vendor (that is, the targeted vendor of the device this + * code is running on). This method merely calls through to + * {@link #nameForVendor(String,String)}, passing the default vendor + * as the second argument. + * + * @param charsetName the base character set name + * @return the specialized character set name, or {@code charsetName} if + * there is no specialized name + */ + public static String nameForDefaultVendor(String charsetName) { + return nameForVendor(charsetName, getDefaultVendor()); + } + + /** + * Returns the vendor-specific character set corresponding to the + * given original character set name and vendor. If there is no + * vendor-specific character set for the given name/vendor pair, + * this returns the character set corresponding to the original + * name. The vendor name is matched case-insensitively. This + * method merely calls {@code Charset.forName()} on a name + * transformed by a call to {@link #nameForVendor(String,String)}. + * + * @param charsetName the base character set name + * @param vendor the vendor to specialize for + * @return the specialized character set, or the one corresponding + * directly to {@code charsetName} if there is no specialized + * variant + * @throws UnsupportedCharsetException thrown if the named character + * set is not supported by the system + * @throws IllegalCharsetNameException thrown if {@code charsetName} + * has invalid syntax + */ + public static Charset charsetForVendor(String charsetName, String vendor) + throws UnsupportedCharsetException, IllegalCharsetNameException { + charsetName = nameForVendor(charsetName, vendor); + return Charset.forName(charsetName); + } + + /** + * Returns the vendor-specific character set corresponding to the + * given original character set name and default vendor (that is, + * the targeted vendor of the device this code is running on). + * This method merely calls through to {@link + * #charsetForVendor(String,String)}, passing the default vendor + * as the second argument. + * + * @param charsetName the base character set name + * @return the specialized character set, or the one corresponding + * directly to {@code charsetName} if there is no specialized + * variant + * @throws UnsupportedCharsetException thrown if the named character + * set is not supported by the system + * @throws IllegalCharsetNameException thrown if {@code charsetName} + * has invalid syntax + */ + public static Charset charsetForVendor(String charsetName) + throws UnsupportedCharsetException, IllegalCharsetNameException { + return charsetForVendor(charsetName, getDefaultVendor()); + } + + /** + * Returns whether the given character set name indicates the Shift-JIS + * encoding. + * + * @param charsetName the character set name + * @return {@code true} if the name corresponds to Shift-JIS or + * {@code false} if not + */ + private static boolean isShiftJis(String charsetName) { + if (charsetName.length() != 9) { + // Bail quickly if the length doesn't match. + return false; + } + + return charsetName.equalsIgnoreCase("shift_jis") + || charsetName.equalsIgnoreCase("shift-jis"); + } + + /** + * Gets the default vendor for this build. + * + * @return the default vendor name + */ + private static String getDefaultVendor() { + return Build.BRAND; + } +} diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java index c0b27f8af017e0d1ad584550f053897e9c5ffe37..9571041f361ecfe233840c3e1bcba7d5a71c90ec 100644 --- a/core/java/android/util/Config.java +++ b/core/java/android/util/Config.java @@ -1,51 +1,59 @@ -/* device/vmlibs-config/release/android/util/Config.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. -*/ +/* + * 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 android.util; /** * Build configuration. The constants in this class vary depending - * on release vs. debug build. This is the configuration for release builds. + * on release vs. debug build. * {@more} */ public final class Config { /** - * Is this a release build? + * If this is a debug build, this field will be true. + */ + public static final boolean DEBUG = ConfigBuildFlags.DEBUG; + + /* + * Deprecated fields + * TODO: Remove platform references to these and @hide them. */ - public static final boolean RELEASE = true; /** - * Is this a debug build? + * Always the inverse of DEBUG. */ - public static final boolean DEBUG = false; + @Deprecated + public static final boolean RELEASE = !DEBUG; /** - * Is profiling enabled? + * Always false. */ + @Deprecated public static final boolean PROFILE = false; - + /** - * Are VERBOSE log messages enabled? + * Always false. */ + @Deprecated public static final boolean LOGV = false; /** - * Are DEBUG log messages enabled? + * Always true. */ + @Deprecated public static final boolean LOGD = true; } diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java index 1c5d669ad52aa18fe99efd5e752156aabad6fcb2..56f389c9faa90fdd42c85ec703d1539c2e969efb 100644 --- a/core/java/android/util/DebugUtils.java +++ b/core/java/android/util/DebugUtils.java @@ -43,8 +43,8 @@ public class DebugUtils { * *

        This class is useful for debugging and logging purpose:

        *
        -     * if (Config.DEBUG) {
        -     *   if (DebugUtils.isObjectSelected(childView) && Config.LOGV) {
        +     * if (DEBUG) {
        +     *   if (DebugUtils.isObjectSelected(childView) && LOGV_ENABLED) {
              *     Log.v(TAG, "Object " + childView + " logged!");
              *   }
              * }
        diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
        index 9de4cbe80665f770ecc3c88979b875773dc64807..e4dd020e1a81812232dba1877d56abd7fea5ec57 100644
        --- a/core/java/android/util/DisplayMetrics.java
        +++ b/core/java/android/util/DisplayMetrics.java
        @@ -31,7 +31,11 @@ public class DisplayMetrics {
              */
             public static final int DEFAULT_DENSITY = 160;
         
        -    private static final int sLcdDensity = SystemProperties.getInt("ro.sf.lcd_density",
        +    /**
        +     * The device's density.
        +     * @hide
        +     */
        +    public static final int DEVICE_DENSITY = SystemProperties.getInt("ro.sf.lcd_density",
                     DEFAULT_DENSITY);
         
             /**
        @@ -90,9 +94,29 @@ public class DisplayMetrics {
             public void setToDefaults() {
                 widthPixels = 0;
                 heightPixels = 0;
        -        density = sLcdDensity / (float) DEFAULT_DENSITY;
        +        density = DEVICE_DENSITY / (float) DEFAULT_DENSITY;
                 scaledDensity = density;
        -        xdpi = sLcdDensity;
        -        ydpi = sLcdDensity;
        +        xdpi = DEVICE_DENSITY;
        +        ydpi = DEVICE_DENSITY;
        +    }
        +
        +    /**
        +     * Set the display metrics' density and update parameters depend on it.
        +     * @hide
        +     */
        +    public void updateDensity(float newDensity) {
        +        float ratio = newDensity / density;
        +        density = newDensity;
        +        scaledDensity = density;
        +        widthPixels *= ratio;
        +        heightPixels *= ratio;
        +        xdpi *= ratio;
        +        ydpi *= ratio;
        +    }
        +
        +    public String toString() {
        +        return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
        +            ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
        +            ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
             }
         }
        diff --git a/core/java/android/util/FinitePool.java b/core/java/android/util/FinitePool.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..3ef82930e9a90d48ac54ae1652abd4a57559244a
        --- /dev/null
        +++ b/core/java/android/util/FinitePool.java
        @@ -0,0 +1,86 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.util;
        +
        +/**
        + * @hide
        + */
        +class FinitePool> implements Pool {
        +    /**
        +     * Factory used to create new pool objects
        +     */
        +    private final PoolableManager mManager;
        +    /**
        +     * Maximum number of objects in the pool
        +     */
        +    private final int mLimit;
        +    /**
        +     * If true, mLimit is ignored
        +     */
        +    private final boolean mInfinite;
        +
        +    /**
        +     * Next object to acquire
        +     */
        +    private T mRoot;
        +    /**
        +     * Number of objects in the pool
        +     */
        +    private int mPoolCount;
        +
        +    FinitePool(PoolableManager manager) {
        +        mManager = manager;
        +        mLimit = 0;
        +        mInfinite = true;
        +    }
        +
        +    FinitePool(PoolableManager manager, int limit) {
        +        if (limit <= 0) throw new IllegalArgumentException("The pool limit must be > 0");
        +
        +        mManager = manager;
        +        mLimit = limit;
        +        mInfinite = false;
        +    }
        +
        +    public T acquire() {
        +        T element;
        +
        +        if (mRoot != null) {
        +            element = mRoot;
        +            mRoot = element.getNextPoolable();
        +            mPoolCount--;
        +        } else {
        +            element = mManager.newInstance();
        +        }
        +
        +        if (element != null) {
        +            element.setNextPoolable(null);
        +            mManager.onAcquired(element);            
        +        }
        +
        +        return element;
        +    }
        +
        +    public void release(T element) {
        +        if (mInfinite || mPoolCount < mLimit) {
        +            mPoolCount++;
        +            element.setNextPoolable(mRoot);
        +            mRoot = element;
        +        }
        +        mManager.onReleased(element);
        +    }
        +}
        diff --git a/core/java/android/util/Pool.java b/core/java/android/util/Pool.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..8cd4f3ed07a05ea2bb95d0c5a33e4932506aa849
        --- /dev/null
        +++ b/core/java/android/util/Pool.java
        @@ -0,0 +1,25 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.util;
        +
        +/**
        + * @hide
        + */
        +public interface Pool> {
        +    public abstract T acquire();
        +    public abstract void release(T element);
        +}
        diff --git a/core/java/android/util/Poolable.java b/core/java/android/util/Poolable.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..fd9bd9b7f136d56ccc7c69d107fe92e54b6d0d24
        --- /dev/null
        +++ b/core/java/android/util/Poolable.java
        @@ -0,0 +1,25 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.util;
        +
        +/**
        + * @hide
        + */
        +public interface Poolable {
        +    void setNextPoolable(T element);
        +    T getNextPoolable();
        +}
        diff --git a/core/java/android/util/PoolableManager.java b/core/java/android/util/PoolableManager.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..8773e6339b31c9782017d5a11415459285bf1f11
        --- /dev/null
        +++ b/core/java/android/util/PoolableManager.java
        @@ -0,0 +1,27 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.util;
        +
        +/**
        + * @hide
        + */
        +public interface PoolableManager> {
        +    T newInstance();
        +
        +    void onAcquired(T element);
        +    void onReleased(T element);
        +}
        diff --git a/core/java/android/util/Pools.java b/core/java/android/util/Pools.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..8edb3e60405ed70f0b97b477b48c53fcab88c631
        --- /dev/null
        +++ b/core/java/android/util/Pools.java
        @@ -0,0 +1,41 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.util;
        +
        +/**
        + * @hide
        + */
        +public class Pools {
        +    private Pools() {
        +    }
        +
        +    public static > Pool simplePool(PoolableManager manager) {
        +        return new FinitePool(manager);
        +    }
        +    
        +    public static > Pool finitePool(PoolableManager manager, int limit) {
        +        return new FinitePool(manager, limit);
        +    }
        +
        +    public static > Pool synchronizedPool(Pool pool) {
        +        return new SynchronizedPool(pool);
        +    }
        +
        +    public static > Pool synchronizedPool(Pool pool, Object lock) {
        +        return new SynchronizedPool(pool, lock);
        +    }
        +}
        diff --git a/core/java/android/util/SynchronizedPool.java b/core/java/android/util/SynchronizedPool.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..651e0c335e8b678b43f29499b9ab74764bcba83c
        --- /dev/null
        +++ b/core/java/android/util/SynchronizedPool.java
        @@ -0,0 +1,48 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.util;
        +
        +/**
        + *
        + * @hide
        + */
        +class SynchronizedPool> implements Pool {
        +    private final Pool mPool;
        +    private final Object mLock;
        +
        +    public SynchronizedPool(Pool pool) {
        +        mPool = pool;
        +        mLock = this;
        +    }
        +
        +    public SynchronizedPool(Pool pool, Object lock) {
        +        mPool = pool;
        +        mLock = lock;
        +    }
        +
        +    public T acquire() {
        +        synchronized (mLock) {
        +            return mPool.acquire();
        +        }
        +    }
        +
        +    public void release(T element) {
        +        synchronized (mLock) {
        +            mPool.release(element);
        +        }
        +    }
        +}
        diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
        index 882a07903741fa4c278f151b0d99c8e7aef09a98..86261c4a7edb90dec61fc2d715dc507ffb7a5bf2 100644
        --- a/core/java/android/view/MotionEvent.java
        +++ b/core/java/android/view/MotionEvent.java
        @@ -102,7 +102,7 @@ public final class MotionEvent implements Parcelable {
             private float mYPrecision;
             private int mDeviceId;
             private int mEdgeFlags;
        -    
        +
             private MotionEvent mNext;
             private RuntimeException mRecycledLocation;
             private boolean mRecycled;
        @@ -210,7 +210,33 @@ public final class MotionEvent implements Parcelable {
         
                 return ev;
             }
        -    
        +
        +    /**
        +     * Scales down the cood of this event by the given scale.
        +     *
        +     * @hide
        +     */
        +    public void scale(float scale) {
        +        if (scale != 1.0f) {
        +            mX *= scale;
        +            mY *= scale;
        +            mRawX *= scale;
        +            mRawY *= scale;
        +            mSize *= scale;
        +            mXPrecision *= scale;
        +            mYPrecision *= scale;
        +            if (mHistory != null) {
        +                float[] history = mHistory;
        +                int length = history.length;
        +                for (int i = 0; i < length; i += 4) {
        +                    history[i] *= scale;
        +                    history[i + 2] *= scale;
        +                    history[i + 3] *= scale;
        +                }
        +            }
        +        }
        +    }
        +
             /**
              * Create a new MotionEvent, copying from an existing one.
              */
        @@ -682,4 +708,3 @@ public final class MotionEvent implements Parcelable {
             }
         
         }
        -
        diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
        index e928998b6d00a83f165bfbb7c002ede92e240625..3d023f7a9691091583812724ec7eca526b4670f0 100644
        --- a/core/java/android/view/SurfaceView.java
        +++ b/core/java/android/view/SurfaceView.java
        @@ -135,20 +135,28 @@ public class SurfaceView extends View {
             int mFormat = -1;
             int mType = -1;
             final Rect mSurfaceFrame = new Rect();
        +    private final float mAppScale;
        +    private final float mAppScaleInverted;
         
             public SurfaceView(Context context) {
                 super(context);
                 setWillNotDraw(true);
        +        mAppScale = context.getApplicationScale();
        +        mAppScaleInverted = 1.0f / mAppScale;
             }
             
             public SurfaceView(Context context, AttributeSet attrs) {
                 super(context, attrs);
                 setWillNotDraw(true);
        +        mAppScale = context.getApplicationScale();
        +        mAppScaleInverted = 1.0f / mAppScale;
             }
         
             public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
                 super(context, attrs, defStyle);
                 setWillNotDraw(true);
        +        mAppScale = context.getApplicationScale();
        +        mAppScaleInverted = 1.0f / mAppScale;
             }
             
             /**
        @@ -247,6 +255,23 @@ public class SurfaceView extends View {
                 super.draw(canvas);
             }
         
        +    @Override
        +    public boolean dispatchTouchEvent(MotionEvent event) {
        +        // SurfaceView uses pre-scaled size unless fixed size is requested. This hook
        +        // scales the event back to the pre-scaled coordinates for such surface.
        +        if (mRequestedWidth < 0 && mAppScale != 1.0f) {
        +            MotionEvent scaledBack = MotionEvent.obtain(event);
        +            scaledBack.scale(mAppScale);
        +            try {
        +                return super.dispatchTouchEvent(scaledBack);
        +            } finally {
        +                scaledBack.recycle();
        +            }
        +        } else {
        +            return super.dispatchTouchEvent(event);
        +        }
        +    }
        +
             @Override
             protected void dispatchDraw(Canvas canvas) {
                 // if SKIP_DRAW is cleared, draw() has already punched a hole
        @@ -269,7 +294,13 @@ public class SurfaceView extends View {
                 if (myWidth <= 0) myWidth = getWidth();
                 int myHeight = mRequestedHeight;
                 if (myHeight <= 0) myHeight = getHeight();
        -        
        +
        +        // Use original size for surface unless fixed size is requested.
        +        if (mRequestedWidth <= 0) {
        +            myWidth *= mAppScale;
        +            myHeight *= mAppScale;
        +        }
        +
                 getLocationInWindow(mLocation);
                 final boolean creating = mWindow == null;
                 final boolean formatChanged = mFormat != mRequestedFormat;
        @@ -295,10 +326,11 @@ public class SurfaceView extends View {
                         mFormat = mRequestedFormat;
                         mType = mRequestedType;
         
        -                mLayout.x = mLeft;
        -                mLayout.y = mTop;
        -                mLayout.width = getWidth();
        -                mLayout.height = getHeight();
        +                // Scaling window's layout here beause mLayout is not used elsewhere.
        +                mLayout.x = (int) (mLeft * mAppScale);
        +                mLayout.y = (int) (mTop * mAppScale);
        +                mLayout.width = (int) (getWidth() * mAppScale);
        +                mLayout.height = (int) (getHeight() * mAppScale);
                         mLayout.format = mRequestedFormat;
                         mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                                       | WindowManager.LayoutParams.FLAG_SCALED
        @@ -325,9 +357,14 @@ public class SurfaceView extends View {
                         mSurfaceLock.lock();
                         mDrawingStopped = !visible;
                         final int relayoutResult = mSession.relayout(
        -                        mWindow, mLayout, mWidth, mHeight,
        +                    mWindow, mLayout, mWidth, mHeight,
                                 visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
                                 mVisibleInsets, mSurface);
        +
        +                mContentInsets.scale(mAppScaleInverted);
        +                mVisibleInsets.scale(mAppScaleInverted);
        +                mWinFrame.scale(mAppScaleInverted);
        +
                         if (localLOGV) Log.i(TAG, "New surface: " + mSurface
                                 + ", vis=" + visible + ", frame=" + mWinFrame);
                         mSurfaceFrame.left = 0;
        @@ -344,7 +381,7 @@ public class SurfaceView extends View {
                                 synchronized (mCallbacks) {
                                     callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
                                     mCallbacks.toArray(callbacks);
        -                        }            
        +                        }
         
                                 if (visibleChanged) {
                                     mIsCreating = true;
        @@ -395,15 +432,25 @@ public class SurfaceView extends View {
             }
         
             private static class MyWindow extends IWindow.Stub {
        -        private WeakReference mSurfaceView;
        +        private final WeakReference mSurfaceView;
        +        private final float mAppScale;
        +        private final float mAppScaleInverted;
         
                 public MyWindow(SurfaceView surfaceView) {
                     mSurfaceView = new WeakReference(surfaceView);
        +            mAppScale = surfaceView.getContext().getApplicationScale();
        +            mAppScaleInverted = 1.0f / mAppScale;
                 }
         
                 public void resized(int w, int h, Rect coveredInsets,
                         Rect visibleInsets, boolean reportDraw) {
                     SurfaceView surfaceView = mSurfaceView.get();
        +            float scale = mAppScaleInverted;
        +            w *= scale;
        +            h *= scale;
        +            coveredInsets.scale(scale);
        +            visibleInsets.scale(scale);
        +
                     if (surfaceView != null) {
                         if (localLOGV) Log.v(
                                 "SurfaceView", surfaceView + " got resized: w=" +
        @@ -566,6 +613,7 @@ public class SurfaceView extends View {
                     Canvas c = null;
                     if (!mDrawingStopped && mWindow != null) {
                         Rect frame = dirty != null ? dirty : mSurfaceFrame;
        +                frame.scale(mAppScale);
                         try {
                             c = mSurface.lockCanvas(frame);
                         } catch (Exception e) {
        @@ -611,4 +659,3 @@ public class SurfaceView extends View {
                 }
             };
         }
        -
        diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
        index 3951b2c323cf205e2f96d448f5a005fbc3291423..c708f547642a5c527562b9e4f1de5d2283ff6b18 100644
        --- a/core/java/android/view/VelocityTracker.java
        +++ b/core/java/android/view/VelocityTracker.java
        @@ -18,6 +18,10 @@ package android.view;
         
         import android.util.Config;
         import android.util.Log;
        +import android.util.Poolable;
        +import android.util.Pool;
        +import android.util.Pools;
        +import android.util.PoolableManager;
         
         /**
          * Helper for tracking the velocity of touch events, for implementing
        @@ -28,53 +32,72 @@ import android.util.Log;
          * {@link #computeCurrentVelocity(int)} and then {@link #getXVelocity()}
          * and {@link #getXVelocity()}.
          */
        -public final class VelocityTracker {
        +public final class VelocityTracker implements Poolable {
             static final String TAG = "VelocityTracker";
             static final boolean DEBUG = false;
             static final boolean localLOGV = DEBUG || Config.LOGV;
        -    
        +
             static final int NUM_PAST = 10;
             static final int LONGEST_PAST_TIME = 200;
        -    
        +
             static final VelocityTracker[] mPool = new VelocityTracker[1];
        -    
        +    private static final Pool sPool = Pools.synchronizedPool(
        +            Pools.finitePool(new PoolableManager() {
        +                public VelocityTracker newInstance() {
        +                    return new VelocityTracker();
        +                }
        +
        +                public void onAcquired(VelocityTracker element) {
        +                    element.clear();
        +                }
        +
        +                public void onReleased(VelocityTracker element) {
        +                }
        +            }, 2));
        +
             final float mPastX[] = new float[NUM_PAST];
             final float mPastY[] = new float[NUM_PAST];
             final long mPastTime[] = new long[NUM_PAST];
        -   
        +
             float mYVelocity;
             float mXVelocity;
        -    
        +
        +    private VelocityTracker mNext;
        +
             /**
              * Retrieve a new VelocityTracker object to watch the velocity of a
              * motion.  Be sure to call {@link #recycle} when done.  You should
              * generally only maintain an active object while tracking a movement,
              * so that the VelocityTracker can be re-used elsewhere.
        -     * 
        +     *
              * @return Returns a new VelocityTracker.
              */
             static public VelocityTracker obtain() {
        -        synchronized (mPool) {
        -            VelocityTracker vt = mPool[0];
        -            if (vt != null) {
        -                vt.clear();
        -                mPool[0] = null;
        -                return vt;
        -            }
        -            return new VelocityTracker();
        -        }
        +        return sPool.acquire();
             }
        -    
        +
             /**
              * Return a VelocityTracker object back to be re-used by others.  You must
              * not touch the object after calling this function.
              */
             public void recycle() {
        -        synchronized (mPool) {
        -            mPool[0] = this;
        -        }
        +        sPool.release(this);
             }
        -    
        +
        +    /**
        +     * @hide
        +     */
        +    public void setNextPoolable(VelocityTracker element) {
        +        mNext = element;
        +    }
        +
        +    /**
        +     * @hide
        +     */
        +    public VelocityTracker getNextPoolable() {
        +        return mNext;
        +    }
        +
             private VelocityTracker() {
             }
             
        diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
        index 0a84aa01d04eaf34c896987fb8bf55fe57438ff5..9e709cfd1f475e7968748191b0ed451fc07c3294 100644
        --- a/core/java/android/view/View.java
        +++ b/core/java/android/view/View.java
        @@ -45,6 +45,11 @@ import android.util.AttributeSet;
         import android.util.EventLog;
         import android.util.Log;
         import android.util.SparseArray;
        +import android.util.Poolable;
        +import android.util.Pool;
        +import android.util.Pools;
        +import android.util.PoolableManager;
        +import android.util.Config;
         import android.view.ContextMenu.ContextMenuInfo;
         import android.view.animation.Animation;
         import android.view.inputmethod.InputConnection;
        @@ -57,7 +62,10 @@ import com.android.internal.view.menu.MenuBuilder;
         
         import java.util.ArrayList;
         import java.util.Arrays;
        +import java.util.WeakHashMap;
         import java.lang.ref.SoftReference;
        +import java.lang.reflect.Method;
        +import java.lang.reflect.InvocationTargetException;
         
         /**
          * 

        @@ -1281,7 +1289,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * a Rect. :) */ static final ThreadLocal sThreadLocal = new ThreadLocal(); - + + /** + * Map used to store views' tags. + */ + private static WeakHashMap> sTags; + + /** + * Lock used to access sTags. + */ + private static final Object sTagsLock = new Object(); + /** * The animation currently associated with this view. * @hide @@ -1387,6 +1405,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ static final int SCROLL_CONTAINER_ADDED = 0x00100000; + /** + * View flag indicating whether this view was invalidated (fully or partially.) + * + * @hide + */ + static final int DIRTY = 0x00200000; + + /** + * View flag indicating whether this view was invalidated by an opaque + * invalidate request. + * + * @hide + */ + static final int DIRTY_OPAQUE = 0x00400000; + + /** + * Mask for {@link #DIRTY} and {@link #DIRTY_OPAQUE}. + * + * @hide + */ + static final int DIRTY_MASK = 0x00600000; + /** * The parent this view is attached to. * {@hide} @@ -1403,7 +1443,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * {@hide} */ - @ViewDebug.ExportedProperty + @ViewDebug.ExportedProperty(flagMapping = { + @ViewDebug.FlagToString(mask = FORCE_LAYOUT, equals = FORCE_LAYOUT, + name = "FORCE_LAYOUT"), + @ViewDebug.FlagToString(mask = LAYOUT_REQUIRED, equals = LAYOUT_REQUIRED, + name = "LAYOUT_REQUIRED"), + @ViewDebug.FlagToString(mask = DRAWING_CACHE_VALID, equals = DRAWING_CACHE_VALID, + name = "DRAWING_CACHE_VALID", outputIf = false), + @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "DRAWN", outputIf = true), + @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "NOT_DRAWN", outputIf = false), + @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), + @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY, name = "DIRTY") + }) int mPrivateFlags; /** @@ -1870,6 +1921,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback { case R.styleable.View_minHeight: mMinHeight = a.getDimensionPixelSize(attr, 0); break; + case R.styleable.View_onClick: + final String handlerName = a.getString(attr); + if (handlerName != null) { + setOnClickListener(new OnClickListener() { + private Method mHandler; + + public void onClick(View v) { + if (mHandler == null) { + try { + mHandler = getContext().getClass().getMethod(handlerName, + View.class); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Could not find a method " + + handlerName + "(View) in the activity", e); + } + } + + try { + mHandler.invoke(getContext(), View.this); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Could not execute non " + + "public method of the activity", e); + } catch (InvocationTargetException e) { + throw new IllegalStateException("Could not execute " + + "method of the activity", e); + } + } + }); + } + break; } } @@ -2420,6 +2501,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { && mAttachInfo.mHasWindowFocus) { imm.focusOut(this); } + onFocusLost(); } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { imm.focusIn(this); @@ -2431,6 +2513,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } } + /** + * Invoked whenever this view loses focus, either by losing window focus or by losing + * focus within its window. This method can be used to clear any state tied to the + * focus. For instance, if a button is held pressed with the trackball and the window + * loses focus, this method can be used to cancel the press. + * + * Subclasses of View overriding this method should always call super.onFocusLost(). + * + * @see #onFocusChanged(boolean, int, android.graphics.Rect) + * @see #onWindowFocusChanged(boolean) + * + * @hide pending API council approval + */ + protected void onFocusLost() { + resetPressedState(); + } + + private void resetPressedState() { + if ((mViewFlags & ENABLED_MASK) == DISABLED) { + return; + } + + if (isPressed()) { + setPressed(false); + + if (!mHasPerformedLongPress) { + if (mPendingCheckForLongPress != null) { + removeCallbacks(mPendingCheckForLongPress); + } + } + } + } + /** * Returns true if this view has focus * @@ -3412,6 +3527,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (mPendingCheckForLongPress != null) { removeCallbacks(mPendingCheckForLongPress); } + onFocusLost(); } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) { imm.focusIn(this); } @@ -4439,6 +4555,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } } + /** + * Indicates whether this View is opaque. An opaque View guarantees that it will + * draw all the pixels overlapping its bounds using a fully opaque color. + * + * Subclasses of View should override this method whenever possible to indicate + * whether an instance is opaque. Opaque Views are treated in a special way by + * the View hierarchy, possibly allowing it to perform optimizations during + * invalidate/draw passes. + * + * @return True if this View is guaranteed to be fully opaque, false otherwise. + * + * @hide Pending API council approval + */ + @ViewDebug.ExportedProperty + public boolean isOpaque() { + return mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE; + } + /** * @return A handler associated with the thread running the View. This * handler can be used to pump events in the UI events queue. @@ -5519,7 +5653,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (ViewDebug.TRACE_HIERARCHY) { ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE); } - if (ViewRoot.PROFILE_DRAWING) { + if (Config.DEBUG && ViewDebug.profileDrawing) { EventLog.writeEvent(60002, hashCode()); } @@ -5605,7 +5739,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { final int restoreCount = canvas.save(); canvas.translate(-mScrollX, -mScrollY); - mPrivateFlags |= DRAWN; + mPrivateFlags = (mPrivateFlags & ~DIRTY_MASK) | DRAWN; // Fast path for layouts with no backgrounds if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { @@ -5631,7 +5765,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Create a snapshot of the view into a bitmap. We should probably make * some form of this public, but should think about the API. */ - /*package*/ Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor) { + Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor) { final int width = mRight - mLeft; final int height = mBottom - mTop; @@ -5793,7 +5927,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); } - mPrivateFlags |= DRAWN; + final boolean dirtyOpaque = (mPrivateFlags & DIRTY_MASK) == DIRTY_OPAQUE; + mPrivateFlags = (mPrivateFlags & ~DIRTY_MASK) | DRAWN; /* * Draw traversal performs several drawing steps which must be executed @@ -5810,22 +5945,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback { // Step 1, draw the background, if needed int saveCount; - final Drawable background = mBGDrawable; - if (background != null) { - final int scrollX = mScrollX; - final int scrollY = mScrollY; + if (!dirtyOpaque) { + final Drawable background = mBGDrawable; + if (background != null) { + final int scrollX = mScrollX; + final int scrollY = mScrollY; - if (mBackgroundSizeChanged) { - background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); - mBackgroundSizeChanged = false; - } + if (mBackgroundSizeChanged) { + background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); + mBackgroundSizeChanged = false; + } - if ((scrollX | scrollY) == 0) { - background.draw(canvas); - } else { - canvas.translate(scrollX, scrollY); - background.draw(canvas); - canvas.translate(-scrollX, -scrollY); + if ((scrollX | scrollY) == 0) { + background.draw(canvas); + } else { + canvas.translate(scrollX, scrollY); + background.draw(canvas); + canvas.translate(-scrollX, -scrollY); + } } } @@ -5835,7 +5972,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; if (!verticalEdges && !horizontalEdges) { // Step 3, draw the content - onDraw(canvas); + if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); @@ -5938,7 +6075,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } // Step 3, draw the content - onDraw(canvas); + if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); @@ -6701,6 +6838,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public void setSelected(boolean selected) { if (((mPrivateFlags & SELECTED) != 0) != selected) { mPrivateFlags = (mPrivateFlags & ~SELECTED) | (selected ? SELECTED : 0); + if (!selected) resetPressedState(); invalidate(); refreshDrawableState(); dispatchSetSelected(selected); @@ -6928,6 +7066,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Returns this view's tag. * * @return the Object stored in this view as a tag + * + * @see #setTag(Object) + * @see #getTag(int) */ @ViewDebug.ExportedProperty public Object getTag() { @@ -6941,11 +7082,155 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * resorting to another data structure. * * @param tag an Object to tag the view with + * + * @see #getTag() + * @see #setTag(int, Object) */ public void setTag(final Object tag) { mTag = tag; } + /** + * Returns the tag associated with this view and the specified key. + * + * @param key The key identifying the tag + * + * @return the Object stored in this view as a tag + * + * @see #setTag(int, Object) + * @see #getTag() + */ + public Object getTag(int key) { + SparseArray tags = null; + synchronized (sTagsLock) { + if (sTags != null) { + tags = sTags.get(this); + } + } + + if (tags != null) return tags.get(key); + return null; + } + + /** + * Sets a tag associated with this view and a key. A tag can be used + * to mark a view in its hierarchy and does not have to be unique within + * the hierarchy. Tags can also be used to store data within a view + * without resorting to another data structure. + * + * The specified key should be an id declared in the resources of the + * application to ensure it is unique. Keys identified as belonging to + * the Android framework or not associated with any package will cause + * an {@link IllegalArgumentException} to be thrown. + * + * @param key The key identifying the tag + * @param tag An Object to tag the view with + * + * @throws IllegalArgumentException If they specified key is not valid + * + * @see #setTag(Object) + * @see #getTag(int) + */ + public void setTag(int key, final Object tag) { + // If the package id is 0x00 or 0x01, it's either an undefined package + // or a framework id + if ((key >>> 24) < 2) { + throw new IllegalArgumentException("The key must be an application-specific " + + "resource id."); + } + + setTagInternal(this, key, tag); + } + + /** + * Variation of {@link #setTag(int, Object)} that enforces the key to be a + * framework id. + * + * @hide + */ + public void setTagInternal(int key, Object tag) { + if ((key >>> 24) != 0x1) { + throw new IllegalArgumentException("The key must be a framework-specific " + + "resource id."); + } + + setTagInternal(this, key, tag); + } + + private static void setTagInternal(View view, int key, Object tag) { + SparseArray tags = null; + synchronized (sTagsLock) { + if (sTags == null) { + sTags = new WeakHashMap>(); + } else { + tags = sTags.get(view); + } + } + + if (tags == null) { + tags = new SparseArray(2); + synchronized (sTagsLock) { + sTags.put(view, tags); + } + } + + tags.put(key, tag); + } + + /** + * @param consistency The type of consistency. See ViewDebug for more information. + * + * @hide + */ + protected boolean dispatchConsistencyCheck(int consistency) { + return onConsistencyCheck(consistency); + } + + /** + * Method that subclasses should implement to check their consistency. The type of + * consistency check is indicated by the bit field passed as a parameter. + * + * @param consistency The type of consistency. See ViewDebug for more information. + * + * @throws IllegalStateException if the view is in an inconsistent state. + * + * @hide + */ + protected boolean onConsistencyCheck(int consistency) { + boolean result = true; + + final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0; + final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0; + + if (checkLayout) { + if (getParent() == null) { + result = false; + android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, + "View " + this + " does not have a parent."); + } + + if (mAttachInfo == null) { + result = false; + android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, + "View " + this + " is not attached to a window."); + } + } + + if (checkDrawing) { + // Do not check the DIRTY/DRAWN flags because views can call invalidate() + // from their draw() method + + if ((mPrivateFlags & DRAWN) != DRAWN && + (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) { + result = false; + android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, + "View " + this + " was invalidated but its drawing cache is valid."); + } + } + + return result; + } + /** * Prints information about this view in the log output, with the tag * {@link #VIEW_LOG_TAG}. @@ -7887,26 +8172,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * For performance purposes, this class also implements a pool of up to * POOL_LIMIT objects that get reused. This reduces memory allocations * whenever possible. - * - * The pool is implemented as a linked list of InvalidateInfo object with - * the root pointing to the next available InvalidateInfo. If the root - * is null (i.e. when all instances from the pool have been acquired), - * then a new InvalidateInfo is created and returned to the caller. - * - * An InvalidateInfo is sent back to the pool by calling its release() - * method. If the pool is full the object is simply discarded. - * - * This implementation follows the object pool pattern used in the - * MotionEvent class. */ - static class InvalidateInfo { + static class InvalidateInfo implements Poolable { private static final int POOL_LIMIT = 10; - private static final Object sLock = new Object(); + private static final Pool sPool = Pools.synchronizedPool( + Pools.finitePool(new PoolableManager() { + public InvalidateInfo newInstance() { + return new InvalidateInfo(); + } + + public void onAcquired(InvalidateInfo element) { + } - private static int sAcquiredCount = 0; - private static InvalidateInfo sRoot; + public void onReleased(InvalidateInfo element) { + } + }, POOL_LIMIT) + ); - private InvalidateInfo next; + private InvalidateInfo mNext; View target; @@ -7915,28 +8198,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback { int right; int bottom; - static InvalidateInfo acquire() { - synchronized (sLock) { - if (sRoot == null) { - return new InvalidateInfo(); - } + public void setNextPoolable(InvalidateInfo element) { + mNext = element; + } - InvalidateInfo info = sRoot; - sRoot = info.next; - sAcquiredCount--; + public InvalidateInfo getNextPoolable() { + return mNext; + } - return info; - } + static InvalidateInfo acquire() { + return sPool.acquire(); } void release() { - synchronized (sLock) { - if (sAcquiredCount < POOL_LIMIT) { - sAcquiredCount++; - next = sRoot; - sRoot = this; - } - } + sPool.release(this); } } diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 367c9a22d953c9e1cf50f94f224078d700146d0e..74a248f65834dbf0a6360b8faa604e8bedd44a63 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -53,6 +53,27 @@ import java.lang.reflect.AccessibleObject; * Various debugging/tracing tools related to {@link View} and the view hierarchy. */ public class ViewDebug { + /** + * Log tag used to log errors related to the consistency of the view hierarchy. + * + * @hide + */ + public static final String CONSISTENCY_LOG_TAG = "ViewConsistency"; + + /** + * Flag indicating the consistency check should check layout-related properties. + * + * @hide + */ + public static final int CONSISTENCY_LAYOUT = 0x1; + + /** + * Flag indicating the consistency check should check drawing-related properties. + * + * @hide + */ + public static final int CONSISTENCY_DRAWING = 0x2; + /** * Enables or disables view hierarchy tracing. Any invoker of * {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first @@ -79,6 +100,49 @@ public class ViewDebug { */ static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent"; + /** + * Profiles drawing times in the events log. + * + * @hide + */ + @Debug.DebugProperty + public static boolean profileDrawing = false; + + /** + * Profiles layout times in the events log. + * + * @hide + */ + @Debug.DebugProperty + public static boolean profileLayout = false; + + /** + * Profiles real fps (times between draws) and displays the result. + * + * @hide + */ + @Debug.DebugProperty + public static boolean showFps = false; + + /** + *

        Enables or disables views consistency check. Even when this property is enabled, + * view consistency checks happen only if {@link android.util.Config#DEBUG} is set + * to true. The value of this property can be configured externally in one of the + * following files:

        + *
          + *
        • /system/debug.prop
        • + *
        • /debug.prop
        • + *
        • /data/debug.prop
        • + *
        + * @hide + */ + @Debug.DebugProperty + public static boolean consistencyCheckEnabled = false; + + static { + Debug.setFieldsOn(ViewDebug.class, true); + } + /** * 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 @@ -123,7 +187,7 @@ public class ViewDebug { * of an array: * *
        -         * @ViewDebug.ExportedProperty(mapping = {
        +         * @ViewDebug.ExportedProperty(indexMapping = {
                  *     @ViewDebug.IntToString(from = 0, to = "INVALID"),
                  *     @ViewDebug.IntToString(from = 1, to = "FIRST"),
                  *     @ViewDebug.IntToString(from = 2, to = "SECOND")
        @@ -138,6 +202,25 @@ public class ViewDebug {
                  */
                 IntToString[] indexMapping() default { };
         
        +        /**
        +         * A flags mapping can be defined to map flags encoded in an integer to
        +         * specific strings. A mapping can be used to see human readable values
        +         * for the flags of an integer:
        +         *
        +         * 
        +         * @ViewDebug.ExportedProperty(flagMapping = {
        +         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"),
        +         *     @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"),
        +         * })
        +         * private int mFlags;
        +         * 
        +         *
        +         * A specified String is output when the following is true:
        +         * 
        +         * @return An array of int to String mappings
        +         */
        +        FlagToString[] flagMapping() default { };
        +
                 /**
                  * When deep export is turned on, this property is not dumped. Instead, the
                  * properties contained in this property are dumped. Each child property
        @@ -182,7 +265,45 @@ public class ViewDebug {
                  */
                 String to();
             }
        -    
        +
        +    /**
        +     * Defines a mapping from an flag to a String. Such a mapping can be used
        +     * in a @ExportedProperty to provide more meaningful values to the end user.
        +     *
        +     * @see android.view.ViewDebug.ExportedProperty
        +     */
        +    @Target({ ElementType.TYPE })
        +    @Retention(RetentionPolicy.RUNTIME)
        +    public @interface FlagToString {
        +        /**
        +         * The mask to apply to the original value.
        +         *
        +         * @return An arbitrary int value.
        +         */
        +        int mask();
        +
        +        /**
        +         * The value to compare to the result of:
        +         * original value & {@link #mask()}.
        +         *
        +         * @return An arbitrary value.
        +         */
        +        int equals();
        +
        +        /**
        +         * The String to use in place of the original int value.
        +         *
        +         * @return An arbitrary non-null String.
        +         */
        +        String name();
        +
        +        /**
        +         * Indicates whether to output the flag when the test is true,
        +         * or false. Defaults to true.
        +         */
        +        boolean outputIf() default true;
        +    }
        +
             /**
              * 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
        @@ -975,6 +1096,13 @@ public class ViewDebug {
                                 final int id = (Integer) methodValue;
                                 methodValue = resolveId(context, id);
                             } else {
        +                        final FlagToString[] flagsMapping = property.flagMapping();
        +                        if (flagsMapping.length > 0) {
        +                            final int intValue = (Integer) methodValue;
        +                            final String valuePrefix = prefix + method.getName() + '_';
        +                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
        +                        }
        +
                                 final IntToString[] mapping = property.mapping();
                                 if (mapping.length > 0) {
                                     final int intValue = (Integer) methodValue;
        @@ -1036,6 +1164,13 @@ public class ViewDebug {
                                 final int id = field.getInt(view);
                                 fieldValue = resolveId(context, id);
                             } else {
        +                        final FlagToString[] flagsMapping = property.flagMapping();
        +                        if (flagsMapping.length > 0) {
        +                            final int intValue = field.getInt(view);
        +                            final String valuePrefix = prefix + field.getName() + '_';
        +                            exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
        +                        }
        +
                                 final IntToString[] mapping = property.mapping();
                                 if (mapping.length > 0) {
                                     final int intValue = field.getInt(view);
        @@ -1093,6 +1228,22 @@ public class ViewDebug {
                 out.write(' ');
             }
         
        +    private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping,
        +            int intValue, String prefix) throws IOException {
        +
        +        final int count = mapping.length;
        +        for (int j = 0; j < count; j++) {
        +            final FlagToString flagMapping = mapping[j];
        +            final boolean ifTrue = flagMapping.outputIf();
        +            final boolean test = (intValue & flagMapping.mask()) == flagMapping.equals();
        +            if ((test && ifTrue) || (!test && !ifTrue)) {
        +                final String name = flagMapping.name();
        +                final String value = ifTrue ? "true" : "false";
        +                writeEntry(out, prefix, name, "", value);
        +            }
        +        }
        +    }
        +
             private static void exportUnrolledArray(Context context, BufferedWriter out,
                     ExportedProperty property, int[] array, String prefix, String suffix)
                     throws IOException {
        diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
        index e686d1c20bd21eaa050ff3bf9187b549ee7b1355..26fe776ba3506f781c2d593059d41d0f38a6e857 100644
        --- a/core/java/android/view/ViewGroup.java
        +++ b/core/java/android/view/ViewGroup.java
        @@ -32,6 +32,7 @@ import android.util.AttributeSet;
         import android.util.EventLog;
         import android.util.Log;
         import android.util.SparseArray;
        +import android.util.Config;
         import android.view.animation.Animation;
         import android.view.animation.AnimationUtils;
         import android.view.animation.LayoutAnimationController;
        @@ -1404,7 +1405,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         
                 // Clear the flag as early as possible to allow draw() implementations
                 // to call invalidate() successfully when doing animations
        -        child.mPrivateFlags |= DRAWN;
        +        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
         
                 if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
                         (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
        @@ -1494,7 +1495,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                         cachePaint.setAlpha(255);
                         mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
                     }
        -            if (ViewRoot.PROFILE_DRAWING) {
        +            if (Config.DEBUG && ViewDebug.profileDrawing) {
                         EventLog.writeEvent(60003, hashCode());
                     }
                     canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
        @@ -1796,7 +1797,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                     boolean preventRequestLayout) {
                 child.mParent = null;
                 addViewInner(child, index, params, preventRequestLayout);
        -        child.mPrivateFlags |= DRAWN;
        +        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
                 return true;
             }
         
        @@ -2210,7 +2211,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                 addInArray(child, index);
         
                 child.mParent = this;
        -        child.mPrivateFlags |= DRAWN;
        +        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
         
                 if (child.hasFocus()) {
                     requestChildFocus(child, child.findFocus());
        @@ -2320,15 +2321,33 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                     // ourselves and the parent to make sure the invalidate request goes
                     // through
                     final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
        -    
        +
        +            // Check whether the child that requests the invalidate is fully opaque
        +            final boolean isOpaque = child.isOpaque();
        +            // Mark the child as dirty, using the appropriate flag
        +            // Make sure we do not set both flags at the same time
        +            final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
        +
                     do {
        +                View view = null;
        +                if (parent instanceof View) {
        +                    view = (View) parent;
        +                }
        +
                         if (drawAnimation) {
        -                    if (parent instanceof View) {
        -                        ((View) parent).mPrivateFlags |= DRAW_ANIMATION;
        +                    if (view != null) {
        +                        view.mPrivateFlags |= DRAW_ANIMATION;
                             } else if (parent instanceof ViewRoot) {
                                 ((ViewRoot) parent).mIsAnimating = true;
                             }
                         }
        +
        +                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
        +                // flag coming from the child that initiated the invalidate
        +                if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
        +                    view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
        +                }
        +
                         parent = parent.invalidateChildInParent(location, dirty);
                     } while (parent != null);
                 }
        @@ -2731,6 +2750,61 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
             }
         
        +    /**
        +     * @hide
        +     */
        +    @Override
        +    protected boolean dispatchConsistencyCheck(int consistency) {
        +        boolean result = super.dispatchConsistencyCheck(consistency);
        +
        +        final int count = mChildrenCount;
        +        final View[] children = mChildren;
        +        for (int i = 0; i < count; i++) {
        +            if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
        +        }
        +
        +        return result;
        +    }
        +
        +    /**
        +     * @hide
        +     */
        +    @Override
        +    protected boolean onConsistencyCheck(int consistency) {
        +        boolean result = super.onConsistencyCheck(consistency);
        +
        +        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
        +        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
        +
        +        if (checkLayout) {
        +            final int count = mChildrenCount;
        +            final View[] children = mChildren;
        +            for (int i = 0; i < count; i++) {
        +                if (children[i].getParent() != this) {
        +                    result = false;
        +                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
        +                            "View " + children[i] + " has no parent/a parent that is not " + this);
        +                }
        +            }
        +        }
        +
        +        if (checkDrawing) {
        +            // If this group is dirty, check that the parent is dirty as well
        +            if ((mPrivateFlags & DIRTY_MASK) != 0) {
        +                final ViewParent parent = getParent();
        +                if (parent != null && !(parent instanceof ViewRoot)) {
        +                    if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
        +                        result = false;
        +                        android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
        +                                "ViewGroup " + this + " is dirty but its parent is not: " + this);
        +                    }
        +                }
        +            }
        +        }
        +
        +        return result;
        +    }
        +
             /**
              * {@inheritDoc}
              */
        diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
        index 18ee9aeb8f68eb1c48d81eb3b3a7c1626f7559af..5090c56b5edcbba0274e6e784a1d3592633db814 100644
        --- a/core/java/android/view/ViewRoot.java
        +++ b/core/java/android/view/ViewRoot.java
        @@ -75,13 +75,6 @@ public final class ViewRoot extends Handler implements ViewParent,
             private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
             private static final boolean WATCH_POINTER = false;
         
        -    static final boolean PROFILE_DRAWING = false;
        -    private static final boolean PROFILE_LAYOUT = false;
        -    // profiles real fps (times between draws) and displays the result
        -    private static final boolean SHOW_FPS = false;
        -    // used by SHOW_FPS
        -    private static int sDrawTime;
        -
             /**
              * Maximum time we allow the user to roll the trackball enough to generate
              * a key event, before resetting the counters.
        @@ -97,6 +90,8 @@ public final class ViewRoot extends Handler implements ViewParent,
         
             static final ThreadLocal sRunQueues = new ThreadLocal();
         
        +    private static int sDrawTime;    
        +
             long mLastTrackballTime = 0;
             final TrackballAxis mTrackballAxisX = new TrackballAxis();
             final TrackballAxis mTrackballAxisY = new TrackballAxis();
        @@ -128,6 +123,10 @@ public final class ViewRoot extends Handler implements ViewParent,
             int mHeight;
             Rect mDirty; // will be a graphics.Region soon
             boolean mIsAnimating;
        +    // TODO: change these to scalar class.
        +    private float mAppScale;
        +    private float mAppScaleInverted; // = 1.0f / mAppScale
        +    private int[] mWindowLayoutParamsBackup = null;
         
             final View.AttachInfo mAttachInfo;
         
        @@ -384,10 +383,15 @@ public final class ViewRoot extends Handler implements ViewParent,
                     View panelParentView) {
                 synchronized (this) {
                     if (mView == null) {
        +                mView = view;
        +                mAppScale = mView.getContext().getApplicationScale();
        +                if (mAppScale != 1.0f) {
        +                    mWindowLayoutParamsBackup = new int[4];
        +                }
        +                mAppScaleInverted = 1.0f / mAppScale;
                         mWindowAttributes.copyFrom(attrs);
                         mSoftInputMode = attrs.softInputMode;
                         mWindowAttributesChanged = true;
        -                mView = view;
                         mAttachInfo.mRootView = view;
                         if (panelParentView != null) {
                             mAttachInfo.mPanelParentWindowToken
        @@ -400,7 +404,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                         // manager, to make sure we do the relayout before receiving
                         // any other events from the system.
                         requestLayout();
        -                
        +
                         try {
                             res = sWindowSession.add(mWindow, attrs,
                                     getHostVisibility(), mAttachInfo.mContentInsets);
        @@ -411,6 +415,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                             unscheduleTraversals();
                             throw new RuntimeException("Adding window failed", e);
                         }
        +                mAttachInfo.mContentInsets.scale(mAppScaleInverted);
                         mPendingContentInsets.set(mAttachInfo.mContentInsets);
                         mPendingVisibleInsets.set(0, 0, 0, 0);
                         if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
        @@ -472,6 +477,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                 synchronized (this) {
                     int oldSoftInputMode = mWindowAttributes.softInputMode;
                     mWindowAttributes.copyFrom(attrs);
        +
                     if (newView) {
                         mSoftInputMode = attrs.softInputMode;
                         requestLayout();
        @@ -521,11 +527,17 @@ public final class ViewRoot extends Handler implements ViewParent,
             public void invalidateChild(View child, Rect dirty) {
                 checkThread();
                 if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
        -        if (mCurScrollY != 0) {
        +        if (mCurScrollY != 0 || mAppScale != 1.0f) {
                     mTempRect.set(dirty);
        -            mTempRect.offset(0, -mCurScrollY);
        +            if (mCurScrollY != 0) {
        +               mTempRect.offset(0, -mCurScrollY);
        +            }
        +            if (mAppScale != 1.0f) {
        +                mTempRect.scale(mAppScale);
        +            }
                     dirty = mTempRect;
                 }
        +        // TODO: When doing a union with mDirty != empty, we must cancel all the DIRTY_OPAQUE flags
                 mDirty.union(dirty);
                 if (!mWillDrawSoon) {
                     scheduleTraversals();
        @@ -613,8 +625,8 @@ public final class ViewRoot extends Handler implements ViewParent,
                     mLayoutRequested = true;
         
                     Display d = new Display(0);
        -            desiredWindowWidth = d.getWidth();
        -            desiredWindowHeight = d.getHeight();
        +            desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
        +            desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
         
                     // For the very first time, tell the view hierarchy that it
                     // is attached to the window.  Note that at this point the surface
        @@ -683,8 +695,8 @@ public final class ViewRoot extends Handler implements ViewParent,
                             windowResizesToFitContent = true;
         
                             Display d = new Display(0);
        -                    desiredWindowWidth = d.getWidth();
        -                    desiredWindowHeight = d.getHeight();
        +                    desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
        +                    desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
                         }
                     }
         
        @@ -782,7 +794,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                     final Rect frame = mWinFrame;
                     boolean initialized = false;
                     boolean contentInsetsChanged = false;
        -            boolean visibleInsetsChanged = false;
        +            boolean visibleInsetsChanged;
                     try {
                         boolean hadSurface = mSurface.isValid();
                         int fl = 0;
        @@ -792,10 +804,12 @@ public final class ViewRoot extends Handler implements ViewParent,
                                 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                             }
                         }
        -                relayoutResult = sWindowSession.relayout(
        -                    mWindow, params, host.mMeasuredWidth, host.mMeasuredHeight,
        -                    viewVisibility, insetsPending, frame,
        -                    mPendingContentInsets, mPendingVisibleInsets, mSurface);
        +                if (DEBUG_LAYOUT) {
        +                    Log.i(TAG, "host=w:" + host.mMeasuredWidth + ", h:" +
        +                            host.mMeasuredHeight + ", params=" + params);
        +                }
        +                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
        +
                         if (params != null) {
                             params.flags = fl;
                         }
        @@ -862,7 +876,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                     mHeight = frame.height();
         
                     if (initialized) {
        -                mGlCanvas.setViewport(mWidth, mHeight);
        +                mGlCanvas.setViewport((int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
                     }
         
                     boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
        @@ -921,14 +935,22 @@ public final class ViewRoot extends Handler implements ViewParent,
                     if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
                         "ViewRoot", "Laying out " + host + " to (" +
                         host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
        -            long startTime;
        -            if (PROFILE_LAYOUT) {
        +            long startTime = 0L;
        +            if (Config.DEBUG && ViewDebug.profileLayout) {
                         startTime = SystemClock.elapsedRealtime();
                     }
         
                     host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
         
        -            if (PROFILE_LAYOUT) {
        +            if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
        +                if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
        +                    throw new IllegalStateException("The view hierarchy is an inconsistent state,"
        +                            + "please refer to the logs with the tag "
        +                            + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
        +                }
        +            }
        +
        +            if (Config.DEBUG && ViewDebug.profileLayout) {
                         EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
                     }
         
        @@ -944,6 +966,11 @@ public final class ViewRoot extends Handler implements ViewParent,
                                 mTmpLocation[1] + host.mBottom - host.mTop);
         
                         host.gatherTransparentRegion(mTransparentRegion);
        +
        +                // TODO: scale the region, like:
        +                // Region uses native methods. We probabl should have ScalableRegion class.
        +
        +                // Region does not have equals method ?
                         if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
                             mPreviousTransparentRegion.set(mTransparentRegion);
                             // reconfigure window manager
        @@ -974,6 +1001,9 @@ public final class ViewRoot extends Handler implements ViewParent,
                     givenContent.left = givenContent.top = givenContent.right
                             = givenContent.bottom = givenVisible.left = givenVisible.top
                             = givenVisible.right = givenVisible.bottom = 0;
        +            insets.contentInsets.scale(mAppScale);
        +            insets.visibleInsets.scale(mAppScale);
        +
                     attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
                     if (insetsPending || !mLastGivenInsets.equals(insets)) {
                         mLastGivenInsets.set(insets);
        @@ -1113,7 +1143,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                 
                 int yoff;
                 final boolean scrolling = mScroller != null
        -                && mScroller.computeScrollOffset(); 
        +                && mScroller.computeScrollOffset();
                 if (scrolling) {
                     yoff = mScroller.getCurrY();
                 } else {
        @@ -1135,15 +1165,27 @@ public final class ViewRoot extends Handler implements ViewParent,
                             mGL.glEnable(GL_SCISSOR_TEST);
         
                             mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
        -                    canvas.translate(0, -yoff);
                             mView.mPrivateFlags |= View.DRAWN;
        -                    mView.draw(canvas);
        -                    canvas.translate(0, yoff);
        +
        +                    float scale = mAppScale;
        +                    int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
        +                    try {
        +                        canvas.translate(0, -yoff);
        +                        if (scale != 1.0f) {
        +                            canvas.scale(scale, scale);
        +                        }
        +                        mView.draw(canvas);
        +                        if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
        +                            mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
        +                        }
        +                    } finally {
        +                        canvas.restoreToCount(saveCount);
        +                    }
         
                             mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
                             checkEglErrors();
         
        -                    if (SHOW_FPS) {
        +                    if (Config.DEBUG && ViewDebug.showFps) {
                                 int now = (int)SystemClock.elapsedRealtime();
                                 if (sDrawTime != 0) {
                                     nativeShowFPS(canvas, now - sDrawTime);
        @@ -1160,7 +1202,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                 }
         
                 if (fullRedrawNeeded)
        -            dirty.union(0, 0, mWidth, mHeight);
        +            dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
         
                 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
                     Log.v("ViewRoot", "Draw " + mView + "/"
        @@ -1184,7 +1226,7 @@ public final class ViewRoot extends Handler implements ViewParent,
         
                 try {
                     if (!dirty.isEmpty() || mIsAnimating) {
        -                long startTime;
        +                long startTime = 0L;
         
                         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
                             Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w="
        @@ -1192,7 +1234,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                             //canvas.drawARGB(255, 255, 0, 0);
                         }
         
        -                if (PROFILE_DRAWING) {
        +                if (Config.DEBUG && ViewDebug.profileDrawing) {
                             startTime = SystemClock.elapsedRealtime();
                         }
         
        @@ -1212,12 +1254,30 @@ public final class ViewRoot extends Handler implements ViewParent,
                         dirty.setEmpty();
                         mIsAnimating = false;
                         mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
        -                canvas.translate(0, -yoff);
        -                mView.mPrivateFlags |= View.DRAWN;                    
        -                mView.draw(canvas);
        -                canvas.translate(0, yoff);
        +                mView.mPrivateFlags |= View.DRAWN;
        +
        +                float scale = mAppScale;
        +                Context cxt = mView.getContext();
        +                if (DEBUG_DRAW) {
        +                    Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + ", appScale=" + mAppScale);
        +                }
        +                int saveCount =  canvas.save(Canvas.MATRIX_SAVE_FLAG);
        +                try {
        +                    canvas.translate(0, -yoff);
        +                    if (scale != 1.0f) {
        +                        // re-scale this
        +                        canvas.scale(scale, scale);
        +                    }
        +                    mView.draw(canvas);
        +
        +                    if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
        +                        mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
        +                    }
        +                } finally {
        +                    canvas.restoreToCount(saveCount);
        +                }
         
        -                if (SHOW_FPS) {
        +                if (Config.DEBUG && ViewDebug.showFps) {
                             int now = (int)SystemClock.elapsedRealtime();
                             if (sDrawTime != 0) {
                                 nativeShowFPS(canvas, now - sDrawTime);
        @@ -1225,7 +1285,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                             sDrawTime = now;
                         }
         
        -                if (PROFILE_DRAWING) {
        +                if (Config.DEBUG && ViewDebug.profileDrawing) {
                             EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
                         }
                     }
        @@ -1508,6 +1568,9 @@ public final class ViewRoot extends Handler implements ViewParent,
                     } else {
                         didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
                     }
        +            if (event != null) {
        +                event.scale(mAppScaleInverted);
        +            }
         
                     try {
                         boolean handled;
        @@ -1628,7 +1691,8 @@ public final class ViewRoot extends Handler implements ViewParent,
                                 if (mGlWanted && !mUseGL) {
                                     initializeGL();
                                     if (mGlCanvas != null) {
        -                                mGlCanvas.setViewport(mWidth, mHeight);
        +                                mGlCanvas.setViewport((int) (mWidth * mAppScale),
        +                                        (int) (mHeight * mAppScale));
                                     }
                                 }
                             }
        @@ -1828,6 +1892,9 @@ public final class ViewRoot extends Handler implements ViewParent,
                 } else {
                     didFinish = false;
                 }
        +        if (event != null) {
        +            event.scale(mAppScaleInverted);
        +        }
         
                 if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
         
        @@ -2254,6 +2321,30 @@ public final class ViewRoot extends Handler implements ViewParent,
                 return mAudioManager;
             }
         
        +    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
        +            boolean insetsPending) throws RemoteException {
        +
        +        boolean restore = false;
        +        if (params != null && mAppScale != 1.0f) {
        +            restore = true;
        +            params.scale(mAppScale, mWindowLayoutParamsBackup);
        +        }
        +        int relayoutResult = sWindowSession.relayout(
        +                mWindow, params,
        +                (int) (mView.mMeasuredWidth * mAppScale),
        +                (int) (mView.mMeasuredHeight * mAppScale),
        +                viewVisibility, insetsPending, mWinFrame,
        +                mPendingContentInsets, mPendingVisibleInsets, mSurface);
        +        if (restore) {
        +            params.restore(mWindowLayoutParamsBackup);
        +        }
        +
        +        mPendingContentInsets.scale(mAppScaleInverted);
        +        mPendingVisibleInsets.scale(mAppScaleInverted);
        +        mWinFrame.scale(mAppScaleInverted);
        +        return relayoutResult;
        +    }
        +
             /**
              * {@inheritDoc}
              */
        @@ -2322,12 +2413,8 @@ public final class ViewRoot extends Handler implements ViewParent,
                             // to the window manager to make sure it has the correct
                             // animation info.
                             try {
        -                        if ((sWindowSession.relayout(
        -                                    mWindow, mWindowAttributes,
        -                                    mView.mMeasuredWidth, mView.mMeasuredHeight,
        -                                    viewVisibility, false, mWinFrame, mPendingContentInsets,
        -                                    mPendingVisibleInsets, mSurface)
        -                                &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
        +                        if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
        +                                & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
                                     sWindowSession.finishDrawing(mWindow);
                                 }
                             } catch (RemoteException e) {
        @@ -2353,7 +2440,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                 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
        @@ -2361,8 +2448,11 @@ public final class ViewRoot extends Handler implements ViewParent,
                         + " visibleInsets=" + visibleInsets.toShortString()
                         + " reportDraw=" + reportDraw);
                 Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
        -        msg.arg1 = w;
        -        msg.arg2 = h;
        +
        +        coveredInsets.scale(mAppScaleInverted);
        +        visibleInsets.scale(mAppScaleInverted);
        +        msg.arg1 = (int) (w * mAppScaleInverted);
        +        msg.arg2 = (int) (h * mAppScaleInverted);
                 msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
                 sendMessage(msg);
             }
        @@ -2493,7 +2583,7 @@ public final class ViewRoot extends Handler implements ViewParent,
                             sWindowSession.finishKey(mWindow);
                          } catch (RemoteException e) {
                          }
        -            } else if (mIsPointer) {
        +           } else if (mIsPointer) {
                         boolean didFinish;
                         MotionEvent event = mMotionEvent;
                         if (event == null) {
        diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
        index b87cc42f0e0580874cc4aba9b2d32fcb556dadd3..c69c28154c2d7c5ba4ad831b6a8374b94f014a4f 100644
        --- a/core/java/android/view/WindowManager.java
        +++ b/core/java/android/view/WindowManager.java
        @@ -18,6 +18,7 @@ package android.view;
         
         import android.content.pm.ActivityInfo;
         import android.graphics.PixelFormat;
        +import android.graphics.Rect;
         import android.os.IBinder;
         import android.os.Parcel;
         import android.os.Parcelable;
        @@ -953,7 +954,43 @@ public interface WindowManager extends ViewManager {
                     sb.append('}');
                     return sb.toString();
                 }
        -    
        +
        +        /**
        +         * Scale the layout params' coordinates and size.
        +         * Returns the original info as a backup so that the caller can
        +         * restore the layout params;
        +         */
        +        void scale(float scale, int[] backup) {
        +            if (scale != 1.0f) {
        +                backup[0] = x;
        +                backup[1] = y;
        +                x *= scale;
        +                y *= scale;
        +                if (width > 0) {
        +                    backup[2] = width;
        +                    width *= scale;
        +                }
        +                if (height > 0) {
        +                    backup[3] = height;
        +                    height *= scale;
        +                }
        +            }
        +        }
        +
        +        /**
        +         * Restore the layout params' coordinates and size.
        +         */
        +        void restore(int[] backup) {
        +            x = backup[0];
        +            y = backup[1];
        +            if (width > 0) {
        +                width = backup[2];
        +            }
        +            if (height > 0) {
        +                height = backup[3];
        +            }
        +        }
        +
                 private CharSequence mTitle = "";
             }
         }
        diff --git a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
        index fdb6f9d232247c52770380ff68e0d55152efe7f8..158c56e8c34a22d414fb4ae4f3eb7584a94eedcb 100644
        --- a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
        +++ b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
        @@ -28,6 +28,7 @@ public class AccelerateDecelerateInterpolator implements Interpolator {
             public AccelerateDecelerateInterpolator() {
             }
             
        +    @SuppressWarnings({"UnusedDeclaration"})
             public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
             }
             
        diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
        index b9e293f00cc03052a7cf926df2923092612ecd24..dcab743698213146cd033c9bb4772df43db630aa 100644
        --- a/core/java/android/view/animation/AccelerateInterpolator.java
        +++ b/core/java/android/view/animation/AccelerateInterpolator.java
        @@ -26,7 +26,12 @@ import android.util.AttributeSet;
          *
          */
         public class AccelerateInterpolator implements Interpolator {
        +    private final float mFactor;
        +    private final double mDoubleFactor;
        +
             public AccelerateInterpolator() {
        +        mFactor = 1.0f;
        +        mDoubleFactor = 2.0;
             }
             
             /**
        @@ -39,6 +44,7 @@ public class AccelerateInterpolator implements Interpolator {
              */
             public AccelerateInterpolator(float factor) {
                 mFactor = factor;
        +        mDoubleFactor = 2 * mFactor;
             }
             
             public AccelerateInterpolator(Context context, AttributeSet attrs) {
        @@ -46,17 +52,16 @@ public class AccelerateInterpolator implements Interpolator {
                     context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);
                 
                 mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
        -        
        +        mDoubleFactor = 2 * mFactor;
        +
                 a.recycle();
             }
             
             public float getInterpolation(float input) {
                 if (mFactor == 1.0f) {
        -            return (float)(input * input);
        +            return input * input;
                 } else {
        -            return (float)Math.pow(input, 2 * mFactor);
        +            return (float)Math.pow(input, mDoubleFactor);
                 }
             }
        -    
        -    private float mFactor = 1.0f;
         }
        diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
        index ce3cdc5bbecafe323959f7654b4f658a3437fd54..30883827db8ebc86a4797c3f6c93d04b88e37841 100644
        --- a/core/java/android/view/animation/AnimationUtils.java
        +++ b/core/java/android/view/animation/AnimationUtils.java
        @@ -63,15 +63,13 @@ public class AnimationUtils {
                     parser = context.getResources().getAnimation(id);
                     return createAnimationFromXml(context, parser);
                 } catch (XmlPullParserException ex) {
        -            NotFoundException rnf = new NotFoundException(
        -                    "Can't load animation resource ID #0x"
        -                            + Integer.toHexString(id));
        +            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
        +                    Integer.toHexString(id));
                     rnf.initCause(ex);
                     throw rnf;
                 } catch (IOException ex) {
        -            NotFoundException rnf = new NotFoundException(
        -                    "Can't load animation resource ID #0x"
        -                            + Integer.toHexString(id));
        +            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
        +                    Integer.toHexString(id));
                     rnf.initCause(ex);
                     throw rnf;
                 } finally {
        @@ -81,16 +79,17 @@ public class AnimationUtils {
         
             private static Animation createAnimationFromXml(Context c, XmlPullParser parser)
                     throws XmlPullParserException, IOException {
        +
                 return createAnimationFromXml(c, parser, null, Xml.asAttributeSet(parser));
             }
             
        -    private static Animation createAnimationFromXml(Context c, XmlPullParser parser, AnimationSet parent, AttributeSet attrs)
        -    throws XmlPullParserException, IOException {
        +    private static Animation createAnimationFromXml(Context c, XmlPullParser parser,
        +            AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException {
                 
                 Animation anim = null;
          
                 // Make sure we are on a start tag.
        -        int type = parser.getEventType();
        +        int type;
                 int depth = parser.getDepth();
         
                 while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
        @@ -126,23 +125,21 @@ public class AnimationUtils {
         
             }
         
        -    public static LayoutAnimationController loadLayoutAnimation(
        -            Context context, int id) throws NotFoundException {
        +    public static LayoutAnimationController loadLayoutAnimation(Context context, int id)
        +            throws NotFoundException {
                 
                 XmlResourceParser parser = null;
                 try {
                     parser = context.getResources().getAnimation(id);
                     return createLayoutAnimationFromXml(context, parser);
                 } catch (XmlPullParserException ex) {
        -            NotFoundException rnf = new NotFoundException(
        -                    "Can't load animation resource ID #0x" +
        -                            Integer.toHexString(id));
        +            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
        +                    Integer.toHexString(id));
                     rnf.initCause(ex);
                     throw rnf;
                 } catch (IOException ex) {
        -            NotFoundException rnf = new NotFoundException(
        -                    "Can't load animation resource ID #0x" +
        -                            Integer .toHexString(id));
        +            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
        +                    Integer.toHexString(id));
                     rnf.initCause(ex);
                     throw rnf;
                 } finally {
        @@ -150,24 +147,21 @@ public class AnimationUtils {
                 }
             }
         
        -    private static LayoutAnimationController createLayoutAnimationFromXml(
        -            Context c, XmlPullParser parser)
        -            throws XmlPullParserException, IOException {
        -        return createLayoutAnimationFromXml(c, parser,
        -                Xml.asAttributeSet(parser));
        +    private static LayoutAnimationController createLayoutAnimationFromXml(Context c,
        +            XmlPullParser parser) throws XmlPullParserException, IOException {
        +
        +        return createLayoutAnimationFromXml(c, parser, Xml.asAttributeSet(parser));
             }
         
        -    private static LayoutAnimationController createLayoutAnimationFromXml(
        -            Context c, XmlPullParser parser, AttributeSet attrs)
        -            throws XmlPullParserException, IOException {
        +    private static LayoutAnimationController createLayoutAnimationFromXml(Context c,
        +            XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException {
         
                 LayoutAnimationController controller = null;
         
                 int type;
                 int depth = parser.getDepth();
         
        -        while (((type = parser.next()) != XmlPullParser.END_TAG
        -                || parser.getDepth() > depth)
        +        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
                         && type != XmlPullParser.END_DOCUMENT) {
         
                     if (type != XmlPullParser.START_TAG) {
        @@ -181,8 +175,7 @@ public class AnimationUtils {
                     } else if ("gridLayoutAnimation".equals(name)) {
                         controller = new GridLayoutAnimationController(c, attrs);
                     } else {
        -                throw new RuntimeException("Unknown layout animation name: " +
        -                        name);
        +                throw new RuntimeException("Unknown layout animation name: " + name);
                     }
                 }
         
        @@ -197,9 +190,7 @@ public class AnimationUtils {
              * @param fromLeft is the object to be animated coming from the left
              * @return The new animation
              */
        -    public static Animation makeInAnimation(Context c, boolean fromLeft)
        -    {
        -        
        +    public static Animation makeInAnimation(Context c, boolean fromLeft) {
                 Animation a;
                 if (fromLeft) {
                     a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_left);
        @@ -220,9 +211,7 @@ public class AnimationUtils {
              * @param toRight is the object to be animated exiting to the right
              * @return The new animation
              */
        -    public static Animation makeOutAnimation(Context c, boolean toRight)
        -    {   
        -        
        +    public static Animation makeOutAnimation(Context c, boolean toRight) {
                 Animation a;
                 if (toRight) {
                     a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_right);
        @@ -243,9 +232,7 @@ public class AnimationUtils {
              * @param c Context for loading resources
              * @return The new animation
              */
        -    public static Animation makeInChildBottomAnimation(Context c)
        -    {   
        -
        +    public static Animation makeInChildBottomAnimation(Context c) {
                 Animation a;
                 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_child_bottom);
                 a.setInterpolator(new AccelerateInterpolator());
        @@ -261,23 +248,19 @@ public class AnimationUtils {
              * @return The animation object reference by the specified id
              * @throws NotFoundException
              */
        -    public static Interpolator loadInterpolator(Context context, int id)
        -            throws NotFoundException {
        -
        +    public static Interpolator loadInterpolator(Context context, int id) throws NotFoundException {
                 XmlResourceParser parser = null;
                 try {
                     parser = context.getResources().getAnimation(id);
                     return createInterpolatorFromXml(context, parser);
                 } catch (XmlPullParserException ex) {
        -            NotFoundException rnf = new NotFoundException(
        -                    "Can't load animation resource ID #0x"
        -                            + Integer.toHexString(id));
        +            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
        +                    Integer.toHexString(id));
                     rnf.initCause(ex);
                     throw rnf;
                 } catch (IOException ex) {
        -            NotFoundException rnf = new NotFoundException(
        -                    "Can't load animation resource ID #0x"
        -                            + Integer.toHexString(id));
        +            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
        +                    Integer.toHexString(id));
                     rnf.initCause(ex);
                     throw rnf;
                 } finally {
        @@ -287,12 +270,12 @@ public class AnimationUtils {
             }
             
             private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser)
        -    throws XmlPullParserException, IOException {
        +            throws XmlPullParserException, IOException {
                 
                 Interpolator interpolator = null;
          
                 // Make sure we are on a start tag.
        -        int type = parser.getEventType();
        +        int type;
                 int depth = parser.getDepth();
         
                 while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
        @@ -317,6 +300,14 @@ public class AnimationUtils {
                         interpolator = new AccelerateDecelerateInterpolator(c, attrs);
                     }  else if (name.equals("cycleInterpolator")) {
                         interpolator = new CycleInterpolator(c, attrs);
        +            } else if (name.equals("anticipateInterpolator")) {
        +                interpolator = new AnticipateInterpolator(c, attrs);
        +            } else if (name.equals("overshootInterpolator")) {
        +                interpolator = new OvershootInterpolator(c, attrs);
        +            } else if (name.equals("anticipateOvershootInterpolator")) {
        +                interpolator = new AnticipateOvershootInterpolator(c, attrs);
        +            } else if (name.equals("bounceInterpolator")) {
        +                interpolator = new BounceInterpolator(c, attrs);
                     } else {
                         throw new RuntimeException("Unknown interpolator name: " + parser.getName());
                     }
        diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..a6f110e8c4a6952fa3bac71782f23db54e79d43c
        --- /dev/null
        +++ b/core/java/android/view/animation/AnticipateInterpolator.java
        @@ -0,0 +1,56 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.view.animation;
        +
        +import android.content.Context;
        +import android.content.res.TypedArray;
        +import android.util.AttributeSet;
        +
        +/**
        + * An interpolator where the change starts backward then flings forward.
        + */
        +public class AnticipateInterpolator implements Interpolator {
        +    private final float mTension;
        +
        +    public AnticipateInterpolator() {
        +        mTension = 2.0f;
        +    }
        +
        +    /**
        +     * @param tension Amount of anticipation. When tension equals 0.0f, there is
        +     *                no anticipation and the interpolator becomes a simple
        +     *                acceleration interpolator.
        +     */
        +    public AnticipateInterpolator(float tension) {
        +        mTension = tension;
        +    }
        +
        +    public AnticipateInterpolator(Context context, AttributeSet attrs) {
        +        TypedArray a = context.obtainStyledAttributes(attrs,
        +                com.android.internal.R.styleable.AnticipateInterpolator);
        +
        +        mTension =
        +                a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f);
        +
        +        a.recycle();
        +    }
        +
        +    public float getInterpolation(float t) {
        +        // a(t) = t * t * ((tension + 1) * t - tension)
        +        return t * t * ((mTension + 1) * t - mTension);
        +    }
        +}
        diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..3dc972278b78720ad8bebc1e8042fc6c6329c3ba
        --- /dev/null
        +++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
        @@ -0,0 +1,83 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.view.animation;
        +
        +import android.content.Context;
        +import android.content.res.TypedArray;
        +import android.util.AttributeSet;
        +import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_extraTension;
        +import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_tension;
        +import static com.android.internal.R.styleable.AnticipateOvershootInterpolator;
        +
        +/**
        + * An interpolator where the change starts backward then flings forward and overshoots
        + * the target value and finally goes back to the final value.
        + */
        +public class AnticipateOvershootInterpolator implements Interpolator {
        +    private final float mTension;
        +
        +    public AnticipateOvershootInterpolator() {
        +        mTension = 2.0f * 1.5f;
        +    }
        +
        +    /**
        +     * @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
        +     *                there is no anticipation/overshoot and the interpolator becomes
        +     *                a simple acceleration/deceleration interpolator.
        +     */
        +    public AnticipateOvershootInterpolator(float tension) {
        +        mTension = tension * 1.5f;
        +    }
        +
        +    /**
        +     * @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
        +     *                there is no anticipation/overshoot and the interpolator becomes
        +     *                a simple acceleration/deceleration interpolator.
        +     * @param extraTension Amount by which to multiply the tension. For instance,
        +     *                     to get the same overshoot as an OvershootInterpolator with
        +     *                     a tension of 2.0f, you would use an extraTension of 1.5f.
        +     */
        +    public AnticipateOvershootInterpolator(float tension, float extraTension) {
        +        mTension = tension * extraTension;
        +    }
        +
        +    public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
        +        TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator);
        +
        +        mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
        +                a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
        +
        +        a.recycle();
        +    }
        +
        +    private static float a(float t, float s) {
        +        return t * t * ((s + 1) * t - s);
        +    }
        +
        +    private static float o(float t, float s) {
        +        return t * t * ((s + 1) * t + s);
        +    }
        +
        +    public float getInterpolation(float t) {
        +        // a(t, s) = t * t * ((s + 1) * t - s)
        +        // o(t, s) = t * t * ((s + 1) * t + s)
        +        // f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5
        +        // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0
        +        if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
        +        else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
        +    }
        +}
        diff --git a/core/java/android/view/animation/BounceInterpolator.java b/core/java/android/view/animation/BounceInterpolator.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..f79e7303f4787ced2c7f80aa6febb8a6ded8a8e9
        --- /dev/null
        +++ b/core/java/android/view/animation/BounceInterpolator.java
        @@ -0,0 +1,51 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.view.animation;
        +
        +import android.content.Context;
        +import android.content.res.TypedArray;
        +import android.util.AttributeSet;
        +
        +/**
        + * An interpolator where the change bounces at the end.
        + */
        +public class BounceInterpolator implements Interpolator {
        +    public BounceInterpolator() {
        +    }
        +
        +    @SuppressWarnings({"UnusedDeclaration"})
        +    public BounceInterpolator(Context context, AttributeSet attrs) {
        +    }
        +
        +    private static float bounce(float t) {
        +        return t * t * 8.0f;
        +    }
        +
        +    public float getInterpolation(float t) {
        +        // _b(t) = t * t * 8
        +        // bs(t) = _b(t) for t < 0.3535
        +        // bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408
        +        // bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644
        +        // bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0
        +        // b(t) = bs(t * 1.1226)
        +        t *= 1.1226f;
        +        if (t < 0.3535f) return bounce(t);
        +        else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
        +        else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
        +        else return bounce(t - 1.0435f) + 0.95f;
        +    }
        +}
        \ No newline at end of file
        diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
        new file mode 100644
        index 0000000000000000000000000000000000000000..494f8ab5a05b2df7916a43239b6f0da068436225
        --- /dev/null
        +++ b/core/java/android/view/animation/OvershootInterpolator.java
        @@ -0,0 +1,59 @@
        +/*
        + * Copyright (C) 2009 The Android Open Source Project
        + *
        + * Licensed under the Apache License, Version 2.0 (the "License");
        + * you may not use this file except in compliance with the License.
        + * You may obtain a copy of the License at
        + *
        + *      http://www.apache.org/licenses/LICENSE-2.0
        + *
        + * Unless required by applicable law or agreed to in writing, software
        + * distributed under the License is distributed on an "AS IS" BASIS,
        + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        + * See the License for the specific language governing permissions and
        + * limitations under the License.
        + */
        +
        +package android.view.animation;
        +
        +import android.content.Context;
        +import android.content.res.TypedArray;
        +import android.util.AttributeSet;
        +
        +/**
        + * An interpolator where the change flings forward and overshoots the last value
        + * then comes back.
        + */
        +public class OvershootInterpolator implements Interpolator {
        +    private final float mTension;
        +
        +    public OvershootInterpolator() {
        +        mTension = 2.0f;
        +    }
        +
        +    /**
        +     * @param tension Amount of overshoot. When tension equals 0.0f, there is
        +     *                no overshoot and the interpolator becomes a simple
        +     *                deceleration interpolator.
        +     */
        +    public OvershootInterpolator(float tension) {
        +        mTension = tension;
        +    }
        +
        +    public OvershootInterpolator(Context context, AttributeSet attrs) {
        +        TypedArray a = context.obtainStyledAttributes(attrs,
        +                com.android.internal.R.styleable.OvershootInterpolator);
        +
        +        mTension =
        +                a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f);
        +
        +        a.recycle();
        +    }
        +
        +    public float getInterpolation(float t) {
        +        // _o(t) = t * t * ((tension + 1) * t + tension)
        +        // o(t) = _o(t - 1) + 1
        +        t -= 1.0f;
        +        return t * t * ((mTension + 1) * t + mTension) + 1.0f;
        +    }
        +}
        diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
        index f9e85bf4e46380a3523abb7a074b49e5ac9dcb39..cf210c8b614d548987a827f545eaaf5e583ac73e 100644
        --- a/core/java/android/view/animation/Transformation.java
        +++ b/core/java/android/view/animation/Transformation.java
        @@ -18,6 +18,8 @@ package android.view.animation;
         
         import android.graphics.Matrix;
         
        +import java.io.PrintWriter;
        +
         /**
          * Defines the transformation to be applied at
          * one point in time of an Animation.
        @@ -134,14 +136,38 @@ public class Transformation {
             
             @Override
             public String toString() {
        -        return "Transformation{alpha=" + mAlpha + " matrix="
        -                + mMatrix.toShortString() + "}";
        +        StringBuilder sb = new StringBuilder(64);
        +        sb.append("Transformation");
        +        toShortString(sb);
        +        return sb.toString();
             }
             
             /**
              * Return a string representation of the transformation in a compact form.
              */
             public String toShortString() {
        -        return "{alpha=" + mAlpha + " matrix=" + mMatrix.toShortString() + "}";
        +        StringBuilder sb = new StringBuilder(64);
        +        toShortString(sb);
        +        return sb.toString();
        +    }
        +    
        +    /**
        +     * @hide
        +     */
        +    public void toShortString(StringBuilder sb) {
        +        sb.append("{alpha="); sb.append(mAlpha);
        +        sb.append(" matrix="); mMatrix.toShortString(sb);
        +        sb.append('}');
        +    }
        +    
        +    /**
        +     * Print short string, to optimize dumping.
        +     * @hide
        +     */
        +    public void printShortString(PrintWriter pw) {
        +        pw.print("{alpha="); pw.print(mAlpha);
        +        pw.print(" matrix=");
        +        mMatrix.printShortString(pw);
        +        pw.print('}');
             }
         }
        diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
        index 5401a6e0af12a220f5d8ebd69edc94ffec0100d7..ba3f78cf22ecb7cdbed7bac293d09c08b3efea10 100644
        --- a/core/java/android/webkit/BrowserFrame.java
        +++ b/core/java/android/webkit/BrowserFrame.java
        @@ -24,7 +24,6 @@ import android.net.WebAddress;
         import android.net.http.SslCertificate;
         import android.os.Handler;
         import android.os.Message;
        -import android.util.Config;
         import android.util.Log;
         import android.util.TypedValue;
         
        @@ -120,7 +119,7 @@ class BrowserFrame extends Handler {
                 mDatabase = WebViewDatabase.getInstance(context);
                 mWebViewCore = w;
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
                 }
             }
        @@ -331,7 +330,7 @@ class BrowserFrame extends Handler {
                 switch (msg.what) {
                     case FRAME_COMPLETED: {
                         if (mSettings.getSavePassword() && hasPasswordField()) {
        -                    if (Config.DEBUG) {
        +                    if (WebView.DEBUG) {
                                 Assert.assertNotNull(mCallbackProxy.getBackForwardList()
                                         .getCurrentItem());
                             }
        @@ -480,7 +479,7 @@ class BrowserFrame extends Handler {
                     }
                     if (mSettings.getSavePassword() && hasPasswordField()) {
                         try {
        -                    if (Config.DEBUG) {
        +                    if (WebView.DEBUG) {
                                 Assert.assertNotNull(mCallbackProxy.getBackForwardList()
                                         .getCurrentItem());
                             }
        @@ -528,7 +527,7 @@ class BrowserFrame extends Handler {
                 // is this resource the main-frame top-level page?
                 boolean isMainFramePage = mIsMainFrame;
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
                             + method + ", postData=" + postData + ", isHighPriority="
                             + isHighPriority + ", isMainFramePage=" + isMainFramePage);
        diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
        index 4528b73aa78893a15a902973d70706d3eaa5b9c9..7897435df2fc2e1c233b4c0f25122d12338375aa 100644
        --- a/core/java/android/webkit/CacheManager.java
        +++ b/core/java/android/webkit/CacheManager.java
        @@ -19,7 +19,6 @@ package android.webkit;
         import android.content.Context;
         import android.net.http.Headers;
         import android.os.FileUtils;
        -import android.util.Config;
         import android.util.Log;
         import java.io.File;
         import java.io.FileInputStream;
        @@ -322,7 +321,7 @@ public final class CacheManager {
                     }
                 }
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "getCacheFile for url " + url);
                 }
         
        @@ -416,7 +415,7 @@ public final class CacheManager {
         
                 mDataBase.addCache(url, cacheRet);
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "saveCacheFile for url " + url);
                 }
             }
        diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
        index 0f9f29cedb6d6df8ecef5626730402caf52048c0..17d3f9407f337ecb3a1e3b35d523d5b2c2b118d4 100644
        --- a/core/java/android/webkit/CallbackProxy.java
        +++ b/core/java/android/webkit/CallbackProxy.java
        @@ -30,7 +30,6 @@ import android.os.Handler;
         import android.os.Message;
         import android.os.SystemClock;
         import android.provider.Browser;
        -import android.util.Config;
         import android.util.Log;
         import android.view.KeyEvent;
         import android.view.LayoutInflater;
        @@ -99,6 +98,7 @@ class CallbackProxy extends Handler {
             private static final int SCALE_CHANGED        = 123;
             private static final int RECEIVED_CERTIFICATE = 124;
             private static final int SWITCH_OUT_HISTORY   = 125;
        +    private static final int JS_TIMEOUT           = 126;
         
             // Message triggered by the client to resume execution
             private static final int NOTIFY               = 200;
        @@ -531,6 +531,18 @@ class CallbackProxy extends Handler {
                         }
                         break;
         
        +            case JS_TIMEOUT:
        +                if(mWebChromeClient != null) {
        +                    final JsResult res = (JsResult) msg.obj;
        +                    if(mWebChromeClient.onJsTimeout()) {
        +                        res.confirm();
        +                    } else {
        +                        res.cancel();
        +                    }
        +                    res.setReady();
        +                }
        +                break;
        +
                     case RECEIVED_CERTIFICATE:
                         mWebView.setCertificate((SslCertificate) msg.obj);
                         break;
        @@ -822,7 +834,7 @@ class CallbackProxy extends Handler {
                     String password, Message resumeMsg) {
                 // resumeMsg should be null at this point because we want to create it
                 // within the CallbackProxy.
        -        if (Config.DEBUG) {
        +        if (WebView.DEBUG) {
                     junit.framework.Assert.assertNull(resumeMsg);
                 }
                 resumeMsg = obtainMessage(NOTIFY);
        @@ -1023,4 +1035,26 @@ class CallbackProxy extends Handler {
                 }
                 return result.getResult();
             }
        +
        +    /**
        +     * @hide pending API council approval
        +     */
        +    public boolean onJsTimeout() {
        +        //always interrupt timedout JS by default
        +        if (mWebChromeClient == null) {
        +            return true;
        +        }
        +        JsResult result = new JsResult(this, true);
        +        Message timeout = obtainMessage(JS_TIMEOUT, result);
        +        synchronized (this) {
        +            sendMessage(timeout);
        +            try {
        +                wait();
        +            } catch (InterruptedException e) {
        +                Log.e(LOGTAG, "Caught exception while waiting for jsUnload");
        +                Log.e(LOGTAG, Log.getStackTraceString(e));
        +            }
        +        }
        +        return result.getResult();
        +    }
         }
        diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
        index d90a2fdbd11b1abc12ac56f8fa2fe3440fa716fe..e8c22798bd55bfa1030f8f9a8c665dcf4349b69b 100644
        --- a/core/java/android/webkit/CookieManager.java
        +++ b/core/java/android/webkit/CookieManager.java
        @@ -18,7 +18,6 @@ package android.webkit;
         
         import android.net.ParseException;
         import android.net.WebAddress;
        -import android.util.Config;
         import android.util.Log;
         
         import java.util.ArrayList;
        @@ -263,7 +262,7 @@ public final class CookieManager {
                 if (!mAcceptCookie || uri == null) {
                     return;
                 }
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "setCookie: uri: " + uri + " value: " + value);
                 }
         
        @@ -428,12 +427,12 @@ public final class CookieManager {
                     }
                 }
                 if (ret.length() > 0) {
        -            if (Config.LOGV) {
        +            if (WebView.LOGV_ENABLED) {
                         Log.v(LOGTAG, "getCookie: uri: " + uri + " value: " + ret);
                     }
                     return ret.toString();
                 } else {
        -            if (Config.LOGV) {
        +            if (WebView.LOGV_ENABLED) {
                         Log.v(LOGTAG, "getCookie: uri: " + uri
                                 + " But can't find cookie.");
                     }
        @@ -589,7 +588,7 @@ public final class CookieManager {
                     Iterator> listIter = cookieLists.iterator();
                     while (listIter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
                         ArrayList list = listIter.next();
        -                if (Config.DEBUG) {
        +                if (WebView.DEBUG) {
                             Iterator iter = list.iterator();
                             while (iter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
                                 Cookie cookie = iter.next();
        @@ -609,7 +608,7 @@ public final class CookieManager {
         
                 ArrayList retlist = new ArrayList();
                 if (mapSize >= MAX_RAM_DOMAIN_COUNT || count >= MAX_RAM_COOKIES_COUNT) {
        -            if (Config.DEBUG) {
        +            if (WebView.DEBUG) {
                         Log.v(LOGTAG, count + " cookies used " + byteCount
                                 + " bytes with " + mapSize + " domains");
                     }
        @@ -617,7 +616,7 @@ public final class CookieManager {
                     int toGo = mapSize / 10 + 1;
                     while (toGo-- > 0){
                         String domain = domains[toGo].toString();
        -                if (Config.LOGV) {
        +                if (WebView.LOGV_ENABLED) {
                             Log.v(LOGTAG, "delete domain: " + domain
                                     + " from RAM cache");
                         }
        @@ -648,8 +647,6 @@ public final class CookieManager {
                             // another file in the local web server directory. Still
                             // "localhost" is the best pseudo domain name.
                             ret[0] = "localhost";
        -                } else if (!ret[0].equals("localhost")) {
        -                    return null;
                         }
                     } else if (index == ret[0].lastIndexOf(PERIOD)) {
                         // cookie host must have at least two periods
        diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
        index f2511d84d18f2ed74fb5ba258fa5a2e83a480e28..8d66529f24b93e8203aa30cfe50dd22de3d10487 100644
        --- a/core/java/android/webkit/CookieSyncManager.java
        +++ b/core/java/android/webkit/CookieSyncManager.java
        @@ -17,7 +17,6 @@
         package android.webkit;
         
         import android.content.Context;
        -import android.util.Config;
         import android.util.Log;
         import android.webkit.CookieManager.Cookie;
         
        @@ -162,7 +161,7 @@ public final class CookieSyncManager extends WebSyncManager {
             }
         
             protected void syncFromRamToFlash() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
                 }
         
        @@ -179,7 +178,7 @@ public final class CookieSyncManager extends WebSyncManager {
                         CookieManager.getInstance().deleteLRUDomain();
                 syncFromRamToFlash(lruList);
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE");
                 }
             }
        diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
        index 42d03f0dcc99b648ee242f165574aff203636b10..6f1b160479505aaec852906bd492413316e548df 100644
        --- a/core/java/android/webkit/FrameLoader.java
        +++ b/core/java/android/webkit/FrameLoader.java
        @@ -18,7 +18,6 @@ package android.webkit;
         
         import android.net.http.EventHandler;
         import android.net.http.RequestHandle;
        -import android.util.Config;
         import android.util.Log;
         import android.webkit.CacheManager.CacheResult;
         
        @@ -121,7 +120,7 @@ class FrameLoader {
                 } else if (handleLocalFile(url, mListener, mSettings)) {
                     return true;
                 }
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "FrameLoader.executeLoad: url protocol not supported:"
                             + mListener.url());
                 }
        @@ -181,7 +180,7 @@ class FrameLoader {
                     return true;
                 }
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
                             + mListener.url());
                 }
        @@ -212,7 +211,7 @@ class FrameLoader {
              * setup a load from the byte stream in a CacheResult.
              */
             private void startCacheLoad(CacheResult result) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "FrameLoader: loading from cache: "
                           + mListener.url());
                 }
        @@ -286,7 +285,7 @@ class FrameLoader {
                     // of it's state. If it is not in the cache, then go to the 
                     // network.
                     case WebSettings.LOAD_CACHE_ELSE_NETWORK: {
        -                if (Config.LOGV) {
        +                if (WebView.LOGV_ENABLED) {
                             Log.v(LOGTAG, "FrameLoader: checking cache: "
                                     + mListener.url());
                         }
        diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
        index a0049ac982e2576c3aa465f06b3b97d9f708c913..2a84683cdc86b28e366831035de3d3775d6e07bf 100644
        --- a/core/java/android/webkit/JWebCoreJavaBridge.java
        +++ b/core/java/android/webkit/JWebCoreJavaBridge.java
        @@ -18,7 +18,6 @@ package android.webkit;
         
         import android.os.Handler;
         import android.os.Message;
        -import android.util.Config;
         import android.util.Log;
         
         final class JWebCoreJavaBridge extends Handler {
        @@ -156,7 +155,7 @@ final class JWebCoreJavaBridge extends Handler {
              * @param timemillis The relative time when the timer should fire
              */
             private void setSharedTimer(long timemillis) {
        -        if (Config.LOGV) Log.v(LOGTAG, "setSharedTimer " + timemillis);
        +        if (WebView.LOGV_ENABLED) Log.v(LOGTAG, "setSharedTimer " + timemillis);
         
                 if (timemillis <= 0) {
                     // we don't accumulate the sharedTimer unless it is a delayed
        @@ -180,7 +179,7 @@ final class JWebCoreJavaBridge extends Handler {
              * Stop the shared timer.
              */
             private void stopSharedTimer() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "stopSharedTimer removing all timers");
                 }
                 removeMessages(TIMER_MESSAGE);
        diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
        index c64200cd5b2a13ef57575a2acbd7c799ac843f45..d583eb18a0435de7ee307e8d348e4bb5d7f05c5a 100644
        --- a/core/java/android/webkit/LoadListener.java
        +++ b/core/java/android/webkit/LoadListener.java
        @@ -29,7 +29,6 @@ import android.net.http.SslCertificate;
         
         import android.os.Handler;
         import android.os.Message;
        -import android.util.Config;
         import android.util.Log;
         import android.webkit.CacheManager.CacheResult;
         
        @@ -134,7 +133,7 @@ class LoadListener extends Handler implements EventHandler {
         
             LoadListener(Context context, BrowserFrame frame, String url,
                     int nativeLoader, boolean synchronous, boolean isMainPageLoader) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener constructor url=" + url);
                 }
                 mContext = context;
        @@ -285,7 +284,7 @@ class LoadListener extends Handler implements EventHandler {
              * directly
              */
             public void headers(Headers headers) {
        -        if (Config.LOGV) Log.v(LOGTAG, "LoadListener.headers");
        +        if (WebView.LOGV_ENABLED) Log.v(LOGTAG, "LoadListener.headers");
                 sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS, headers));
             }
         
        @@ -432,7 +431,7 @@ class LoadListener extends Handler implements EventHandler {
              */
             public void status(int majorVersion, int minorVersion,
                     int code, /* Status-Code value */ String reasonPhrase) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener: from: " + mUrl
                             + " major: " + majorVersion
                             + " minor: " + minorVersion
        @@ -489,7 +488,7 @@ class LoadListener extends Handler implements EventHandler {
              * directly
              */
             public void error(int id, String description) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.error url:" +
                             url() + " id:" + id + " description:" + description);
                 }
        @@ -517,7 +516,7 @@ class LoadListener extends Handler implements EventHandler {
              * mDataBuilder is a thread-safe structure.
              */
             public void data(byte[] data, int length) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.data(): url: " + url());
                 }
         
        @@ -555,7 +554,7 @@ class LoadListener extends Handler implements EventHandler {
              * directly
              */
             public void endData() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.endData(): url: " + url());
                 }
                 sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
        @@ -608,7 +607,7 @@ class LoadListener extends Handler implements EventHandler {
                         // before calling it.
                         if (mCacheLoader != null) {
                             mCacheLoader.load();
        -                    if (Config.LOGV) {
        +                    if (WebView.LOGV_ENABLED) {
                                 Log.v(LOGTAG, "LoadListener cache load url=" + url());
                             }
                             return;
        @@ -658,7 +657,7 @@ class LoadListener extends Handler implements EventHandler {
                             CacheManager.HEADER_KEY_IFNONEMATCH) &&
                             !headers.containsKey(
                                     CacheManager.HEADER_KEY_IFMODIFIEDSINCE)) {
        -                if (Config.LOGV) {
        +                if (WebView.LOGV_ENABLED) {
                             Log.v(LOGTAG, "FrameLoader: HTTP URL in cache " +
                                     "and usable: " + url());
                         }
        @@ -677,7 +676,7 @@ class LoadListener extends Handler implements EventHandler {
              * directly
              */
             public void handleSslErrorRequest(SslError error) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG,
                             "LoadListener.handleSslErrorRequest(): url:" + url() +
                             " primary error: " + error.getPrimaryError() +
        @@ -743,7 +742,7 @@ class LoadListener extends Handler implements EventHandler {
              * are null, cancel the request.
              */
             void handleAuthResponse(String username, String password) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.handleAuthResponse: url: " + mUrl
                             + " username: " + username
                             + " password: " + password);
        @@ -840,7 +839,7 @@ class LoadListener extends Handler implements EventHandler {
             }
         
             void attachRequestHandle(RequestHandle requestHandle) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.attachRequestHandle(): " +
                             "requestHandle: " +  requestHandle);
                 }
        @@ -848,7 +847,7 @@ class LoadListener extends Handler implements EventHandler {
             }
         
             void detachRequestHandle() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.detachRequestHandle(): " +
                             "requestHandle: " + mRequestHandle);
                 }
        @@ -887,7 +886,7 @@ class LoadListener extends Handler implements EventHandler {
              */
             static boolean willLoadFromCache(String url) {
                 boolean inCache = CacheManager.getCacheFile(url, null) != null;
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "willLoadFromCache: " + url + " in cache: " + 
                             inCache);
                 }
        @@ -1057,7 +1056,7 @@ class LoadListener extends Handler implements EventHandler {
              * EventHandler's method call.
              */
             public void cancel() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     if (mRequestHandle == null) {
                         Log.v(LOGTAG, "LoadListener.cancel(): no requestHandle");
                     } else {
        @@ -1189,7 +1188,7 @@ class LoadListener extends Handler implements EventHandler {
                     tearDown();
                 }
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.onRedirect(): redirect to: " +
                             redirectTo);
                 }
        @@ -1203,7 +1202,7 @@ class LoadListener extends Handler implements EventHandler {
                     Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
         
             private void parseContentTypeHeader(String contentType) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "LoadListener.parseContentTypeHeader: " +
                             "contentType: " + contentType);
                 }
        @@ -1390,7 +1389,7 @@ class LoadListener extends Handler implements EventHandler {
              */
             private String guessMimeTypeFromExtension() {
                 // PENDING: need to normalize url
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "guessMimeTypeFromExtension: mURL = " + mUrl);
                 }
         
        @@ -1425,7 +1424,7 @@ class LoadListener extends Handler implements EventHandler {
              * Cycle through our messages for synchronous loads.
              */
             /* package */ void loadSynchronousMessages() {
        -        if (Config.DEBUG && !mSynchronous) {
        +        if (WebView.DEBUG && !mSynchronous) {
                     throw new AssertionError();
                 }
                 // Note: this can be called twice if it is a synchronous network load,
        diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
        index 6fa07753dea3350dbcfbb6ac4dc171b5f59bc784..c9b80ce77df60d6d83e35df83f78e023a9eafc2b 100644
        --- a/core/java/android/webkit/Network.java
        +++ b/core/java/android/webkit/Network.java
        @@ -20,7 +20,6 @@ import android.content.Context;
         import android.net.http.*;
         import android.os.*;
         import android.util.Log;
        -import android.util.Config;
         
         import java.io.ByteArrayInputStream;
         import java.io.InputStream;
        @@ -133,7 +132,7 @@ class Network {
              * XXX: Must be created in the same thread as WebCore!!!!!
              */
             private Network(Context context) {
        -        if (Config.DEBUG) {
        +        if (WebView.DEBUG) {
                     Assert.assertTrue(Thread.currentThread().
                             getName().equals(WebViewCore.THREAD_NAME));
                 }
        @@ -233,7 +232,7 @@ class Network {
              * connecting through the proxy.
              */
             public synchronized void setProxyUsername(String proxyUsername) {
        -        if (Config.DEBUG) {
        +        if (WebView.DEBUG) {
                     Assert.assertTrue(isValidProxySet());
                 }
         
        @@ -253,7 +252,7 @@ class Network {
              * connecting through the proxy.
              */
             public synchronized void setProxyPassword(String proxyPassword) {
        -        if (Config.DEBUG) {
        +        if (WebView.DEBUG) {
                     Assert.assertTrue(isValidProxySet());
                 }
         
        @@ -267,7 +266,7 @@ class Network {
              * @return True iff succeeds.
              */
             public boolean saveState(Bundle outState) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "Network.saveState()");
                 }
         
        @@ -281,7 +280,7 @@ class Network {
              * @return True iff succeeds.
              */
             public boolean restoreState(Bundle inState) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "Network.restoreState()");
                 }
         
        @@ -301,7 +300,7 @@ class Network {
              * @param loader The loader that resulted in SSL errors.
              */
             public void handleSslErrorRequest(LoadListener loader) {
        -        if (Config.DEBUG) Assert.assertNotNull(loader);
        +        if (WebView.DEBUG) Assert.assertNotNull(loader);
                 if (loader != null) {
                     mSslErrorHandler.handleSslErrorRequest(loader);
                 }
        @@ -314,7 +313,7 @@ class Network {
              * authentication request.
              */
             public void handleAuthRequest(LoadListener loader) {
        -        if (Config.DEBUG) Assert.assertNotNull(loader);
        +        if (WebView.DEBUG) Assert.assertNotNull(loader);
                 if (loader != null) {
                     mHttpAuthHandler.handleAuthRequest(loader);
                 }
        diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
        index 2e2fa12052abb74919dbc3f6d61b996e15681297..5f84bbe04dd3cdcfa19f5d77f14353073f376781 100644
        --- a/core/java/android/webkit/SslErrorHandler.java
        +++ b/core/java/android/webkit/SslErrorHandler.java
        @@ -22,7 +22,6 @@ import android.net.http.SslError;
         import android.os.Bundle;
         import android.os.Handler;
         import android.os.Message;
        -import android.util.Config;
         import android.util.Log;
         
         import java.util.LinkedList;
        @@ -121,7 +120,7 @@ public class SslErrorHandler extends Handler {
              * Handles SSL error(s) on the way up to the user.
              */
             /* package */ synchronized void handleSslErrorRequest(LoadListener loader) {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "SslErrorHandler.handleSslErrorRequest(): " +
                           "url=" + loader.url());
                 }
        @@ -158,14 +157,14 @@ public class SslErrorHandler extends Handler {
         
                     SslError error = loader.sslError();
         
        -            if (Config.DEBUG) {
        +            if (WebView.DEBUG) {
                         Assert.assertNotNull(error);
                     }
         
                     int primary = error.getPrimaryError();
                     String host = loader.host();
         
        -            if (Config.DEBUG) {
        +            if (WebView.DEBUG) {
                         Assert.assertTrue(host != null && primary != 0);
                     }
         
        @@ -206,11 +205,11 @@ public class SslErrorHandler extends Handler {
              */
             /* package */ synchronized void handleSslErrorResponse(boolean proceed) {
                 LoadListener loader = mLoaderQueue.poll();
        -        if (Config.DEBUG) {
        +        if (WebView.DEBUG) {
                     Assert.assertNotNull(loader);
                 }
         
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "SslErrorHandler.handleSslErrorResponse():"
                           + " proceed: " + proceed
                           + " url:" + loader.url());
        @@ -222,7 +221,7 @@ public class SslErrorHandler extends Handler {
                         int primary = loader.sslError().getPrimaryError();
                         String host = loader.host();
         
        -                if (Config.DEBUG) {
        +                if (WebView.DEBUG) {
                             Assert.assertTrue(host != null && primary != 0);
                         }
                         boolean hasKey = mSslPrefTable.containsKey(host);
        diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
        index 9098307e80524ec1b01e9d47c3eecb7a2b0e41e0..705157c639f29c918ffb0cde27a45ff0e0ef58e3 100644
        --- a/core/java/android/webkit/StreamLoader.java
        +++ b/core/java/android/webkit/StreamLoader.java
        @@ -20,7 +20,6 @@ import android.net.http.EventHandler;
         import android.net.http.Headers;
         import android.os.Handler;
         import android.os.Message;
        -import android.util.Config;
         
         import java.io.IOException;
         import java.io.InputStream;
        @@ -114,7 +113,7 @@ abstract class StreamLoader extends Handler {
              * @see android.os.Handler#handleMessage(android.os.Message)
              */
             public void handleMessage(Message msg) {
        -        if (Config.DEBUG && mHandler.isSynchronous()) {
        +        if (WebView.DEBUG && mHandler.isSynchronous()) {
                     throw new AssertionError();
                 }
                 switch(msg.what) {
        diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
        index 0e8144edd60a20ed638df09994b5a5643e0717f9..d6ac3e9093bfcac04d0e754497e4a7cddfcbfa7c 100644
        --- a/core/java/android/webkit/URLUtil.java
        +++ b/core/java/android/webkit/URLUtil.java
        @@ -23,7 +23,6 @@ import java.util.regex.Pattern;
         import android.net.Uri;
         import android.net.ParseException;
         import android.net.WebAddress;
        -import android.util.Config;
         import android.util.Log;
         
         public final class URLUtil {
        @@ -62,7 +61,7 @@ public final class URLUtil {
                     webAddress = new WebAddress(inUrl);
                 } catch (ParseException ex) {
         
        -            if (Config.LOGV) {
        +            if (WebView.LOGV_ENABLED) {
                         Log.v(LOGTAG, "smartUrlFilter: failed to parse url = " + inUrl);
                     }
                     return retVal;
        diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
        index 9dea5ecbecd44e8940d34b3c4398a165aff7acee..ffd6a118d9e63914a1bc18b9a79f5b06cfa5546e 100644
        --- a/core/java/android/webkit/WebBackForwardList.java
        +++ b/core/java/android/webkit/WebBackForwardList.java
        @@ -16,7 +16,6 @@
         
         package android.webkit;
         
        -import android.util.Config;
         import java.io.Serializable;
         import java.util.ArrayList;
         
        @@ -138,7 +137,7 @@ public class WebBackForwardList implements Cloneable, Serializable {
                 // 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
                 // native BackForwardList.
        -        if (Config.DEBUG && (index != 0)) {
        +        if (WebView.DEBUG && (index != 0)) {
                     throw new AssertionError();
                 }
                 final WebHistoryItem h = mArray.remove(index);
        diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
        index f9400061190b80c16ce8b420407242e24eb62322..9d9763ca66737a19e32839949bc6fc2e0e595b0b 100644
        --- a/core/java/android/webkit/WebChromeClient.java
        +++ b/core/java/android/webkit/WebChromeClient.java
        @@ -157,4 +157,19 @@ public class WebChromeClient {
                     JsResult result) {
                 return false;
             }
        +
        +    /**
        +     * Tell the client that a JavaScript execution timeout has occured. And the
        +     * client may decide whether or not to interrupt the execution. If the
        +     * client returns true, the JavaScript will be interrupted. If the client
        +     * returns false, the execution will continue. Note that in the case of
        +     * continuing execution, the timeout counter will be reset, and the callback
        +     * will continue to occur if the script does not finish at the next check
        +     * point.
        +     * @return boolean Whether the JavaScript execution should be interrupted.
        +     * @hide pending API Council approval
        +     */
        +    public boolean onJsTimeout() {
        +        return true;
        +    }
         }
        diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
        index 025e6bb819cca370f64fbbc2e0b249591f48459d..105eacdca7544d14735a2b1cc7f4735df56a4b2e 100644
        --- a/core/java/android/webkit/WebSettings.java
        +++ b/core/java/android/webkit/WebSettings.java
        @@ -1097,7 +1097,7 @@ public class WebSettings {
             /*package*/
             synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) {
                 mBrowserFrame = frame;
        -        if (android.util.Config.DEBUG) {
        +        if (WebView.DEBUG) {
                     junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
                 }
                 nativeSync(frame.mNativeFrame);
        diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
        index e6e9994486be0fcbea2dcab157aa9c2319e129bb..ded17ed518c781196aa6cd3435def8ce969fad2e 100644
        --- a/core/java/android/webkit/WebSyncManager.java
        +++ b/core/java/android/webkit/WebSyncManager.java
        @@ -21,7 +21,6 @@ import android.os.Handler;
         import android.os.Looper;
         import android.os.Message;
         import android.os.Process;
        -import android.util.Config;
         import android.util.Log;
         
         abstract class WebSyncManager implements Runnable {
        @@ -48,7 +47,7 @@ abstract class WebSyncManager implements Runnable {
                 @Override
                 public void handleMessage(Message msg) {
                     if (msg.what == SYNC_MESSAGE) {
        -                if (Config.LOGV) {
        +                if (WebView.LOGV_ENABLED) {
                             Log.v(LOGTAG, "*** WebSyncManager sync ***");
                         }
                         syncFromRamToFlash();
        @@ -95,7 +94,7 @@ abstract class WebSyncManager implements Runnable {
              * sync() forces sync manager to sync now
              */
             public void sync() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "*** WebSyncManager sync ***");
                 }
                 if (mHandler == null) {
        @@ -110,7 +109,7 @@ abstract class WebSyncManager implements Runnable {
              * resetSync() resets sync manager's timer
              */
             public void resetSync() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "*** WebSyncManager resetSync ***");
                 }
                 if (mHandler == null) {
        @@ -125,7 +124,7 @@ abstract class WebSyncManager implements Runnable {
              * startSync() requests sync manager to start sync
              */
             public void startSync() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "***  WebSyncManager startSync ***, Ref count:" + 
                             mStartSyncRefCount);
                 }
        @@ -143,7 +142,7 @@ abstract class WebSyncManager implements Runnable {
              * the queue to break the sync loop
              */
             public void stopSync() {
        -        if (Config.LOGV) {
        +        if (WebView.LOGV_ENABLED) {
                     Log.v(LOGTAG, "*** WebSyncManager stopSync ***, Ref count:" + 
                             mStartSyncRefCount);
                 }
        diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
        index a5846ed077787dad12b7efdf0a51be8066330b86..563d819d301f4976e5958cde70bf97bc4afe1d0a 100644
        --- a/core/java/android/webkit/WebView.java
        +++ b/core/java/android/webkit/WebView.java
        @@ -21,6 +21,7 @@ import android.content.Context;
         import android.content.DialogInterface;
         import android.content.Intent;
         import android.content.DialogInterface.OnCancelListener;
        +import android.database.DataSetObserver;
         import android.graphics.Bitmap;
         import android.graphics.Canvas;
         import android.graphics.Color;
        @@ -42,7 +43,6 @@ import android.text.IClipboard;
         import android.text.Selection;
         import android.text.Spannable;
         import android.util.AttributeSet;
        -import android.util.Config;
         import android.util.EventLog;
         import android.util.Log;
         import android.view.Gravity;
        @@ -61,6 +61,7 @@ import android.view.inputmethod.InputMethodManager;
         import android.webkit.TextDialog.AutoCompleteAdapter;
         import android.webkit.WebViewCore.EventHub;
         import android.widget.AbsoluteLayout;
        +import android.widget.Adapter;
         import android.widget.AdapterView;
         import android.widget.ArrayAdapter;
         import android.widget.FrameLayout;
        @@ -110,7 +111,7 @@ public class WebView extends AbsoluteLayout
             // keep debugging parameters near the top of the file
             static final String LOGTAG = "webview";
             static final boolean DEBUG = false;
        -    static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
        +    static final boolean LOGV_ENABLED = DEBUG;
         
             private class ExtendedZoomControls extends FrameLayout {
                 public ExtendedZoomControls(Context context, AttributeSet attrs) {
        @@ -4810,7 +4811,10 @@ public class WebView extends AbsoluteLayout
         
                     @Override
                     public boolean hasStableIds() {
        -                return true;
        +                // AdapterView's onChanged method uses this to determine whether
        +                // to restore the old state.  Return false so that the old (out
        +                // of date) state does not replace the new, valid state.
        +                return false;
                     }
         
                     private Container item(int position) {
        @@ -4874,6 +4878,51 @@ public class WebView extends AbsoluteLayout
                     }
                 }
         
        +        /*
        +         * Whenever the data set changes due to filtering, this class ensures
        +         * that the checked item remains checked.
        +         */
        +        private class SingleDataSetObserver extends DataSetObserver {
        +            private long        mCheckedId;
        +            private ListView    mListView;
        +            private Adapter     mAdapter;
        +
        +            /*
        +             * Create a new observer.
        +             * @param id The ID of the item to keep checked.
        +             * @param l ListView for getting and clearing the checked states
        +             * @param a Adapter for getting the IDs
        +             */
        +            public SingleDataSetObserver(long id, ListView l, Adapter a) {
        +                mCheckedId = id;
        +                mListView = l;
        +                mAdapter = a;
        +            }
        +
        +            public void onChanged() {
        +                // The filter may have changed which item is checked.  Find the
        +                // item that the ListView thinks is checked.
        +                int position = mListView.getCheckedItemPosition();
        +                long id = mAdapter.getItemId(position);
        +                if (mCheckedId != id) {
        +                    // Clear the ListView's idea of the checked item, since
        +                    // it is incorrect
        +                    mListView.clearChoices();
        +                    // Search for mCheckedId.  If it is in the filtered list,
        +                    // mark it as checked
        +                    int count = mAdapter.getCount();
        +                    for (int i = 0; i < count; i++) {
        +                        if (mAdapter.getItemId(i) == mCheckedId) {
        +                            mListView.setItemChecked(i, true);
        +                            break;
        +                        }
        +                    }
        +                }
        +            }
        +
        +            public void onInvalidate() {}
        +        }
        +
                 public void run() {
                     final ListView listView = (ListView) LayoutInflater.from(mContext)
                             .inflate(com.android.internal.R.layout.select_dialog, null);
        @@ -4902,8 +4951,7 @@ public class WebView extends AbsoluteLayout
                     // filtered.  Do not allow filtering on multiple lists until
                     // that bug is fixed.
                     
        -            // Disable filter altogether
        -            // listView.setTextFilterEnabled(!mMultiple);
        +            listView.setTextFilterEnabled(!mMultiple);
                     if (mMultiple) {
                         listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
                         int length = mSelectedArray.length;
        @@ -4923,6 +4971,9 @@ public class WebView extends AbsoluteLayout
                             listView.setSelection(mSelection);
                             listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
                             listView.setItemChecked(mSelection, true);
        +                    DataSetObserver observer = new SingleDataSetObserver(
        +                            adapter.getItemId(mSelection), listView, adapter);
        +                    adapter.registerDataSetObserver(observer);
                         }
                     }
                     dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
        diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
        index 72b30f65f1f5a1ed2985f4df3d3f3dc719fff667..e9df453b78f126bc8964977470bc1083cea9d10e 100644
        --- a/core/java/android/webkit/WebViewCore.java
        +++ b/core/java/android/webkit/WebViewCore.java
        @@ -29,7 +29,6 @@ import android.os.Handler;
         import android.os.Looper;
         import android.os.Message;
         import android.os.Process;
        -import android.util.Config;
         import android.util.Log;
         import android.util.SparseBooleanArray;
         import android.view.KeyEvent;
        @@ -43,7 +42,7 @@ final class WebViewCore {
         
             private static final String LOGTAG = "webcore";
             static final boolean DEBUG = false;
        -    static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
        +    static final boolean LOGV_ENABLED = DEBUG;
         
             static {
                 // Load libwebcore during static initialization. This happens in the
        @@ -264,6 +263,16 @@ final class WebViewCore {
                 return mCallbackProxy.onJsBeforeUnload(url, message);
             }
         
        +    /**
        +     *
        +     * Callback to notify that a JavaScript execution timeout has occured.
        +     * @return True if the JavaScript execution should be interrupted. False
        +     *         will continue the execution.
        +     */
        +    protected boolean jsInterrupt() {
        +        return mCallbackProxy.onJsTimeout();
        +    }
        +
             //-------------------------------------------------------------------------
             // JNI methods
             //-------------------------------------------------------------------------
        diff --git a/core/java/android/webkit/gears/AndroidRadioDataProvider.java b/core/java/android/webkit/gears/AndroidRadioDataProvider.java
        index c920d45e4966659536bb6e3f73e0bf96112750e6..2d431a8d6162eff92da00ae7e5b5f3c7a29fbb69 100644
        --- a/core/java/android/webkit/gears/AndroidRadioDataProvider.java
        +++ b/core/java/android/webkit/gears/AndroidRadioDataProvider.java
        @@ -46,6 +46,9 @@ public final class AndroidRadioDataProvider extends PhoneStateListener {
           private static final int RADIO_TYPE_UNKNOWN = 0;
           private static final int RADIO_TYPE_GSM = 1;
           private static final int RADIO_TYPE_WCDMA = 2;
        +  private static final int RADIO_TYPE_CDMA = 3;
        +  private static final int RADIO_TYPE_EVDO = 4;
        +  private static final int RADIO_TYPE_1xRTT = 5;
         
           /** Simple container for radio data */
           public static final class RadioData {
        @@ -102,12 +105,21 @@ public final class AndroidRadioDataProvider extends PhoneStateListener {
               }
         
               // Finally get the radio type.
        +      //TODO We have to edit the parameter for getNetworkType regarding CDMA
               int type = telephonyManager.getNetworkType();
               if (type == TelephonyManager.NETWORK_TYPE_UMTS) {
                 radioData.radioType = RADIO_TYPE_WCDMA;
               } else if (type == TelephonyManager.NETWORK_TYPE_GPRS
                          || type == TelephonyManager.NETWORK_TYPE_EDGE) {
                 radioData.radioType = RADIO_TYPE_GSM;
        +      } else if (type == TelephonyManager.NETWORK_TYPE_CDMA) {
        +          radioData.radioType = RADIO_TYPE_CDMA;
        +      } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_0) {
        +          radioData.radioType = RADIO_TYPE_EVDO;
        +      } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_A) {
        +          radioData.radioType = RADIO_TYPE_EVDO;
        +      } else if (type == TelephonyManager.NETWORK_TYPE_1xRTT) {
        +          radioData.radioType = RADIO_TYPE_1xRTT;
               }
         
               // Print out what we got.
        diff --git a/core/java/android/webkit/gears/AndroidWifiDataProvider.java b/core/java/android/webkit/gears/AndroidWifiDataProvider.java
        index 7379f595358870dca401bdb2ec71270f18260153..d2850b0603866036ef8ab32d92c9da979169fc75 100644
        --- a/core/java/android/webkit/gears/AndroidWifiDataProvider.java
        +++ b/core/java/android/webkit/gears/AndroidWifiDataProvider.java
        @@ -33,7 +33,6 @@ 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;
        @@ -47,6 +46,11 @@ public final class AndroidWifiDataProvider extends BroadcastReceiver {
            * Logging tag
            */
           private static final String TAG = "Gears-J-WifiProvider";
        +  /**
        +   * Flag for guarding Log.v() calls.
        +   * Set to true to enable extra debug logging.
        +   */
        +  private static final boolean LOGV_ENABLED = false;
           /**
            * Our Wifi manager instance.
            */
        @@ -104,7 +108,7 @@ public final class AndroidWifiDataProvider extends BroadcastReceiver {
            */
           public void shutdown() {
             mContext.unregisterReceiver(this);
        -    if (Config.LOGV) {
        +    if (LOGV_ENABLED) {
               Log.v(TAG, "Wifi provider closed.");
             }
           }
        @@ -118,7 +122,7 @@ public final class AndroidWifiDataProvider extends BroadcastReceiver {
           public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals(
                     mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
        -      if (Config.LOGV) {
        +      if (LOGV_ENABLED) {
                 Log.v(TAG, "Wifi scan resulst available");
               }
               onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
        diff --git a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java b/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
        index 529e666dbb8e04a19aed4cfc9fab48f42e5f5e65..74d27edd29b9770a168fc9071daa82afeb5ff998 100644
        --- a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
        +++ b/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
        @@ -29,7 +29,6 @@ import android.net.http.Headers;
         import android.os.Handler;
         import android.os.Looper;
         import android.os.Message;
        -import android.util.Config;
         import android.util.Log;
         import android.webkit.CacheManager;
         import android.webkit.CacheManager.CacheResult;
        @@ -88,6 +87,8 @@ import java.util.concurrent.locks.ReentrantLock;
         public final class ApacheHttpRequestAndroid {
             /** Debug logging tag. */
             private static final String LOG_TAG = "Gears-J";
        +    /** Flag for guarding Log.v() calls. */
        +    private static final boolean LOGV_ENABLED = false;
             /** HTTP response header line endings are CR-LF style. */
             private static final String HTTP_LINE_ENDING = "\r\n";
             /** Safe MIME type to use whenever it isn't specified. */
        @@ -173,18 +174,18 @@ public final class ApacheHttpRequestAndroid {
                 public void run() {
                     boolean problem = false;
                     try {
        -                if (Config.LOGV) {
        +                if (LOGV_ENABLED) {
                             Log.i(LOG_TAG, "REQUEST : " + mMethod.getRequestLine());
                         }
                         mResponse = mClient.execute(mMethod);
                         if (mResponse != null) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "response (status line): "
                                       + mResponse.getStatusLine());
                             }
                             mResponseLine = "" + mResponse.getStatusLine();
                         } else {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "problem, response == null");
                             }
                             problem = true;
        @@ -198,7 +199,7 @@ public final class ApacheHttpRequestAndroid {
                     }
         
                     if (!problem) {
        -                if (Config.LOGV) {
        +                if (LOGV_ENABLED) {
                             Log.i(LOG_TAG, "Request complete ("
                                   + mMethod.getRequestLine() + ")");
                         }
        @@ -206,7 +207,7 @@ public final class ApacheHttpRequestAndroid {
                         mConnectionFailedLock.lock();
                         mConnectionFailed = true;
                         mConnectionFailedLock.unlock();
        -                if (Config.LOGV) {
        +                if (LOGV_ENABLED) {
                             Log.i(LOG_TAG, "Request FAILED ("
                                   + mMethod.getRequestLine() + ")");
                         }
        @@ -233,7 +234,7 @@ public final class ApacheHttpRequestAndroid {
                         try {
                             wait();
                         } catch (InterruptedException e) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "InterruptedException while putting " +
                                     "a DataPacket in the Buffer: " + e);
                             }
        @@ -248,7 +249,7 @@ public final class ApacheHttpRequestAndroid {
                         try {
                             wait();
                         } catch (InterruptedException e) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                               Log.i(LOG_TAG, "InterruptedException while getting " +
                                   "a DataPacket in the Buffer: " + e);
                             }
        @@ -271,7 +272,7 @@ public final class ApacheHttpRequestAndroid {
                         try {
                             wait();
                         } catch (InterruptedException e) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "InterruptedException while waiting " +
                                     "until a DataPacket is consumed: " + e);
                             }
        @@ -285,7 +286,7 @@ public final class ApacheHttpRequestAndroid {
                         try {
                             wait();
                         } catch (InterruptedException e) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "InterruptedException while indicating "
                                       + "that the DataPacket has been consumed: " + e);
                             }
        @@ -373,14 +374,14 @@ public final class ApacheHttpRequestAndroid {
                         mSignal.packetConsumed();
                         mConnectionFailedLock.lock();
                         if (mConnectionFailed) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "stopping loop on error");
                             }
                             finished = true;
                         }
                         mConnectionFailedLock.unlock();
                     }
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "flushing the outputstream...");
                     }
                     mOutputStream.flush();
        @@ -399,7 +400,7 @@ public final class ApacheHttpRequestAndroid {
                 private void write(DataPacket packet) {
                     try {
                         if (mOutputStream == null) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "NO OUTPUT STREAM !!!");
                             }
                             return;
        @@ -407,7 +408,7 @@ public final class ApacheHttpRequestAndroid {
                         mOutputStream.write(packet.getBytes(), 0, packet.getLength());
                         mOutputStream.flush();
                     } catch (IOException e) {
        -                if (Config.LOGV) {
        +                if (LOGV_ENABLED) {
                             Log.i(LOG_TAG, "exc: " + e);
                         }
                         mConnectionFailedLock.lock();
        @@ -423,7 +424,7 @@ public final class ApacheHttpRequestAndroid {
                             mStreamingReady.await();
                         }
                     } catch (InterruptedException e) {
        -                if (Config.LOGV) {
        +                if (LOGV_ENABLED) {
                             Log.i(LOG_TAG, "InterruptedException in "
                                   + "StreamEntity::isReady() : ", e);
                         }
        @@ -468,7 +469,7 @@ public final class ApacheHttpRequestAndroid {
              *                  False on failure.
              */
             public synchronized boolean open(String method, String url) {
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "open " + method + " " + url);
                 }
                 // Create the client
        @@ -502,7 +503,7 @@ public final class ApacheHttpRequestAndroid {
                 } else if ("DELETE".equalsIgnoreCase(method)) {
                     mMethod = new HttpDelete(url);
                 } else {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "Method " + method + " not supported");
                     }
                     return false;
        @@ -549,7 +550,7 @@ public final class ApacheHttpRequestAndroid {
              * (unless already finished)
              */
             private void waitUntilConnectionFinished() {
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "waitUntilConnectionFinished("
                           + mConnectionFinished + ")");
                 }
        @@ -558,11 +559,11 @@ public final class ApacheHttpRequestAndroid {
                         try {
                             mHttpThread.join();
                             mConnectionFinished = true;
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "http thread joined");
                             }
                         } catch (InterruptedException e) {
        -                    if (Config.LOGV) {
        +                    if (LOGV_ENABLED) {
                                 Log.i(LOG_TAG, "interrupted: " + e);
                             }
                         }
        @@ -596,7 +597,7 @@ public final class ApacheHttpRequestAndroid {
                 Header[] headers = mResponse.getAllHeaders();
                 for (int i = 0; i < headers.length; i++) {
                     Header header = headers[i];
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "header " + header.getName()
                               + " -> " + header.getValue());
                     }
        @@ -615,7 +616,7 @@ public final class ApacheHttpRequestAndroid {
              */
             public synchronized void setRequestHeader(String name, String value) {
                 String[] mapValue = { name, value };
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "setRequestHeader: " + name + " => " + value);
                 }
                 if (name.equalsIgnoreCase(KEY_CONTENT_LENGTH)) {
        @@ -647,7 +648,7 @@ public final class ApacheHttpRequestAndroid {
                 while (it.hasNext()) {
                     // Set the key case-sensitive.
                     String[] entry = it.next();
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "apply header " + entry[HEADERS_MAP_INDEX_KEY] +
                             " => " + entry[HEADERS_MAP_INDEX_VALUE]);
                     }
        @@ -671,7 +672,7 @@ public final class ApacheHttpRequestAndroid {
                         return null;
                     }
                 } else {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "getResponseHeader() called but "
                               + "response not received");
                     }
        @@ -687,7 +688,7 @@ public final class ApacheHttpRequestAndroid {
              */
             public synchronized String getAllResponseHeaders() {
                 if (mResponseHeaders == null) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "getAllResponseHeaders() called but "
                               + "response not received");
                     }
        @@ -715,7 +716,7 @@ public final class ApacheHttpRequestAndroid {
              * @param value The associated value.
              */
             private void setResponseHeader(String name, String value) {
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "Set response header " + name + ": " + value);
                 }
                 String mapValue[] = { name, value };
        @@ -766,7 +767,7 @@ public final class ApacheHttpRequestAndroid {
                 UrlInterceptHandlerGears.ServiceResponse serviceResponse =
                     handler.getServiceResponse(url, mRequestHeaders);
                 if (serviceResponse == null) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "No response in LocalServer");
                     }
                     return false;
        @@ -776,7 +777,7 @@ public final class ApacheHttpRequestAndroid {
                 mBodyInputStream = serviceResponse.getInputStream();
                 mResponseLine = serviceResponse.getStatusLine();
                 mResponseHeaders = serviceResponse.getResponseHeaders();
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "Got response from LocalServer: " + mResponseLine);
                 }
                 return true;
        @@ -803,19 +804,19 @@ public final class ApacheHttpRequestAndroid {
                 CacheResult mCacheResult =
                     CacheManager.getCacheFile(url, cacheRequestHeaders);
                 if (mCacheResult == null) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "No CacheResult for " + url);
                     }
                     return false;
                 }
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "Got CacheResult from browser cache");
                 }
                 // Check for expiry. -1 is "never", otherwise milliseconds since 1970.
                 // Can be compared to System.currentTimeMillis().
                 long expires = mCacheResult.getExpires();
                 if (expires >= 0 && System.currentTimeMillis() >= expires) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "CacheResult expired "
                             + (System.currentTimeMillis() - expires)
                             + " milliseconds ago");
        @@ -827,7 +828,7 @@ public final class ApacheHttpRequestAndroid {
                 mBodyInputStream = mCacheResult.getInputStream();
                 if (mBodyInputStream == null) {
                     // Cache result may have gone away.
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "No mBodyInputStream for CacheResult " + url);
                     }
                     return false;
        @@ -855,7 +856,7 @@ public final class ApacheHttpRequestAndroid {
                 }
                 // Synthesize the response line.
                 mResponseLine = "HTTP/1.1 " + statusCode + " " + statusMessage;
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "Synthesized " + mResponseLine);
                 }
                 // Synthesize the returned headers from cache.
        @@ -914,7 +915,7 @@ public final class ApacheHttpRequestAndroid {
              */
             public synchronized boolean createCacheResult(
                 String url, int responseCode, String mimeType, String encoding) {
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "Making cache entry for " + url);
                 }
                 // Take the headers and parse them into a format needed by
        @@ -935,14 +936,14 @@ public final class ApacheHttpRequestAndroid {
                 mCacheResult = CacheManager.createCacheFile(
                     url, responseCode, cacheHeaders, mimeType, true);
                 if (mCacheResult != null) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "Saving into cache");
                     }
                     mCacheResult.setEncoding(encoding);
                     mCacheResultUrl = url;
                     return true;
                 } else {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "Couldn't create mCacheResult");
                     }
                     return false;
        @@ -960,7 +961,7 @@ public final class ApacheHttpRequestAndroid {
              */
             public synchronized boolean appendCacheResult(byte[] data, int bytes) {
                 if (mCacheResult == null) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "appendCacheResult() called without a "
                               + "CacheResult initialized");
                     }
        @@ -969,7 +970,7 @@ public final class ApacheHttpRequestAndroid {
                 try {
                     mCacheResult.getOutputStream().write(data, 0, bytes);
                 } catch (IOException ex) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "Got IOException writing cache data: " + ex);
                     }
                     return false;
        @@ -984,14 +985,14 @@ public final class ApacheHttpRequestAndroid {
              */
             public synchronized boolean saveCacheResult() {
                 if (mCacheResult == null || mCacheResultUrl == null) {
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "Tried to save cache result but "
                               + "createCacheResult not called");
                     }
                     return false;
                 }
         
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "Saving cache result");
                 }
                 CacheManager.saveCacheFile(mCacheResultUrl, mCacheResult);
        @@ -1006,7 +1007,7 @@ public final class ApacheHttpRequestAndroid {
              * ability to receive a null packet for sendPostData().
              */
             public synchronized void abort() {
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "ABORT CALLED");
                 }
                 if (mMethod != null) {
        @@ -1019,7 +1020,7 @@ public final class ApacheHttpRequestAndroid {
              * thread to complete.
              */
             public synchronized void interrupt() {
        -        if (Config.LOGV) {
        +        if (LOGV_ENABLED) {
                     Log.i(LOG_TAG, "INTERRUPT CALLED");
                 }
                 mConnectionFailedLock.lock();
        @@ -1053,7 +1054,7 @@ public final class ApacheHttpRequestAndroid {
                             mBodyInputStream = entity.getContent();
                         }
                     } catch (IOException inputException) {
        -                if (Config.LOGV) {
        +                if (LOGV_ENABLED) {
                             Log.i(LOG_TAG, "Failed to connect InputStream: "
                                   + inputException);
                         }
        @@ -1062,7 +1063,7 @@ public final class ApacheHttpRequestAndroid {
                     }
                     if (mBodyInputStream == null) {
                         // No error stream either. Treat as a 0 byte response.
        -                if (Config.LOGV) {
        +                if (LOGV_ENABLED) {
                             Log.i(LOG_TAG, "No InputStream");
                         }
                         return 0; // EOF.
        @@ -1081,7 +1082,7 @@ public final class ApacheHttpRequestAndroid {
                     }
                 } catch (IOException e) {
                     // An abort() interrupts us by calling close() on our stream.
        -            if (Config.LOGV) {
        +            if (LOGV_ENABLED) {
                         Log.i(LOG_TAG, "Got IOException in mBodyInputStream.read(): ", e);
                     }
                     ret = -1;
        diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
        index 772ad8971d204b4dea37171af56c9577867fa00c..1ca59b2430c791d6cd363ed340e432588bde4ea9 100644
        --- a/core/java/android/widget/AbsListView.java
        +++ b/core/java/android/widget/AbsListView.java
        @@ -433,7 +433,9 @@ public abstract class AbsListView extends AdapterView implements Te
         
             private InputConnection mDefInputConnection;
             private InputConnectionWrapper mPublicInputConnection;
        -    
        +
        +    private Runnable mClearScrollingCache;
        +
             /**
              * Interface definition for a callback to be invoked when the list or grid
              * has been scrolled.
        @@ -983,18 +985,6 @@ public abstract class AbsListView extends AdapterView implements Te
                 mSelectorRect.setEmpty();
                 invalidate();
             }
        -    
        -    /**
        -     * The list is empty and we need to change the layout, so *really* clear everything out.
        -     * @hide - for AutoCompleteTextView & SearchDialog only
        -     */
        -    /* package */ void resetListAndClearViews() {
        -        rememberSyncState();
        -        removeAllViewsInLayout();
        -        mRecycler.clear();
        -        mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
        -        requestLayout();
        -    }
         
             @Override
             protected int computeVerticalScrollExtent() {
        @@ -1920,6 +1910,7 @@ public abstract class AbsListView extends AdapterView implements Te
                             // User clicked on whitespace, or stopped a fling. It is a scroll.
                             createScrollingCache();
                             mTouchMode = TOUCH_MODE_SCROLL;
        +                    mMotionCorrection = 0;
                             motionPosition = findMotionRow(y);
                             reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
                         }
        @@ -2310,6 +2301,7 @@ public abstract class AbsListView extends AdapterView implements Te
                     }
         
                     if (more) {
        +                invalidate();
                         mLastFlingY = y;
                         post(this);
                     } else {
        @@ -2333,16 +2325,23 @@ public abstract class AbsListView extends AdapterView implements Te
             }
         
             private void clearScrollingCache() {
        -        if (mCachingStarted) {
        -            setChildrenDrawnWithCacheEnabled(false);
        -            if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
        -                setChildrenDrawingCacheEnabled(false);
        -            }
        -            if (!isAlwaysDrawnWithCacheEnabled()) {
        -                invalidate();
        -            }
        -            mCachingStarted = false;
        +        if (mClearScrollingCache == null) {
        +            mClearScrollingCache = new Runnable() {
        +                public void run() {
        +                    if (mCachingStarted) {
        +                        mCachingStarted = false;
        +                        setChildrenDrawnWithCacheEnabled(false);
        +                        if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
        +                            setChildrenDrawingCacheEnabled(false);
        +                        }
        +                        if (!isAlwaysDrawnWithCacheEnabled()) {
        +                            invalidate();
        +                        }
        +                    }
        +                }
        +            };
                 }
        +        post(mClearScrollingCache);
             }
         
             /**
        @@ -2799,7 +2798,7 @@ public abstract class AbsListView extends AdapterView implements Te
                 int screenHeight = getResources().getDisplayMetrics().heightPixels;
                 final int[] xy = new int[2];
                 getLocationOnScreen(xy);
        -        // TODO: The 20 below should come from the theme and be expressed in dip
        +        // TODO: The 20 below should come from the theme
                 // TODO: And the gravity should be defined in the theme as well
                 final int bottomGap = screenHeight - xy[1] - getHeight() + (int) (mDensityScale * 20);
                 if (!mPopup.isShowing()) {
        @@ -3191,7 +3190,7 @@ public abstract class AbsListView extends AdapterView implements Te
                 // Reclaim views on screen
                 for (int i = 0; i < childCount; i++) {
                     View child = getChildAt(i);
        -            AbsListView.LayoutParams lp = (AbsListView.LayoutParams)child.getLayoutParams();
        +            AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();
                     // Don't reclaim header or footer views, or views that should be ignored
                     if (lp != null && mRecycler.shouldRecycleViewType(lp.viewType)) {
                         views.add(child);
        @@ -3205,6 +3204,63 @@ public abstract class AbsListView extends AdapterView implements Te
                 removeAllViewsInLayout();
             }
         
        +    /**
        +     * @hide
        +     */
        +    @Override
        +    protected boolean onConsistencyCheck(int consistency) {
        +        boolean result = super.onConsistencyCheck(consistency);
        +
        +        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
        +
        +        if (checkLayout) {
        +            // The active recycler must be empty
        +            final View[] activeViews = mRecycler.mActiveViews;
        +            int count = activeViews.length;
        +            for (int i = 0; i < count; i++) {
        +                if (activeViews[i] != null) {
        +                    result = false;
        +                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
        +                            "AbsListView " + this + " has a view in its active recycler: " +
        +                                    activeViews[i]);
        +                }
        +            }
        +
        +            // All views in the recycler must NOT be on screen and must NOT have a parent
        +            final ArrayList scrap = mRecycler.mCurrentScrap;
        +            if (!checkScrap(scrap)) result = false;
        +            final ArrayList[] scraps = mRecycler.mScrapViews;
        +            count = scraps.length;
        +            for (int i = 0; i < count; i++) {
        +                if (!checkScrap(scraps[i])) result = false;
        +            }
        +        }
        +
        +        return result;
        +    }
        +
        +    private boolean checkScrap(ArrayList scrap) {
        +        if (scrap == null) return true;
        +        boolean result = true;
        +
        +        final int count = scrap.size();
        +        for (int i = 0; i < count; i++) {
        +            final View view = scrap.get(i);
        +            if (view.getParent() != null) {
        +                result = false;
        +                android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
        +                        " has a view in its scrap heap still attached to a parent: " + view);
        +            }
        +            if (indexOfChild(view) >= 0) {
        +                result = false;
        +                android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
        +                        " has a view in its scrap heap that is also a direct child: " + view);
        +            }
        +        }
        +
        +        return result;
        +    }
        +
             /**
              * Sets the recycler listener to be notified whenever a View is set aside in
              * the recycler for later reuse. This listener can be used to free resources
        diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
        index dfb971e7aa595e65aa380c0e674e3472e7c79d90..a1d16eadc0d8383ed6738d9230ffe58b3357e34a 100644
        --- a/core/java/android/widget/AutoCompleteTextView.java
        +++ b/core/java/android/widget/AutoCompleteTextView.java
        @@ -110,6 +110,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
             private final DropDownItemClickListener mDropDownItemClickListener =
                     new DropDownItemClickListener();
         
        +    private boolean mDropDownAlwaysVisible = false;
        +
        +    private boolean mDropDownDismissedOnCompletion = true;
        +
             private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
             private boolean mOpenBefore;
         
        @@ -123,6 +127,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
             // The widget is attached to a window when mAttachCount > 0
             private int mAttachCount;
         
        +    private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
        +
             public AutoCompleteTextView(Context context) {
                 this(context, null);
             }
        @@ -182,6 +188,28 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
                 setFocusable(true);
         
                 addTextChangedListener(new MyWatcher());
        +
        +        mPassThroughClickListener = new PassThroughClickListener();
        +        super.setOnClickListener(mPassThroughClickListener);
        +    }
        +
        +    @Override
        +    public void setOnClickListener(OnClickListener listener) {
        +        mPassThroughClickListener.mWrapped = listener;
        +    }
        +
        +    /**
        +     * Private hook into the on click event, dispatched from {@link PassThroughClickListener}
        +     */
        +    private void onClickImpl() {
        +        // if drop down should always visible, bring it back in front of the soft
        +        // keyboard when the user touches the text field
        +        if (mDropDownAlwaysVisible
        +                && mPopup.isShowing()
        +                && mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED) {
        +            mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
        +            showDropDown();
        +        }
             }
         
             /**
        @@ -211,6 +239,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
              * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.

        * * @return the width for the drop down list + * + * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth */ public int getDropDownWidth() { return mDropDownWidth; @@ -222,6 +252,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.

        * * @param width the width to use + * + * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth */ public void setDropDownWidth(int width) { mDropDownWidth = width; @@ -231,6 +263,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe *

        Returns the id for the view that the auto-complete drop down list is anchored to.

        * * @return the view's id, or {@link View#NO_ID} if none specified + * + * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor */ public int getDropDownAnchor() { return mDropDownAnchorId; @@ -242,12 +276,172 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * loading a view which is not yet instantiated.

        * * @param id the id to anchor the drop down list view to + * + * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor */ public void setDropDownAnchor(int id) { mDropDownAnchorId = id; mDropDownAnchorView = null; } + + /** + *

        Gets the background of the auto-complete drop-down list.

        + * + * @return the background drawable + * + * @attr ref android.R.styleable#PopupWindow_popupBackground + * + * @hide Pending API council approval + */ + public Drawable getDropDownBackground() { + return mPopup.getBackground(); + } + + /** + *

        Sets the background of the auto-complete drop-down list.

        + * + * @param d the drawable to set as the background + * + * @attr ref android.R.styleable#PopupWindow_popupBackground + * + * @hide Pending API council approval + */ + public void setDropDownBackgroundDrawable(Drawable d) { + mPopup.setBackgroundDrawable(d); + } + + /** + *

        Sets the background of the auto-complete drop-down list.

        + * + * @param id the id of the drawable to set as the background + * + * @attr ref android.R.styleable#PopupWindow_popupBackground + * + * @hide Pending API council approval + */ + public void setDropDownBackgroundResource(int id) { + mPopup.setBackgroundDrawable(getResources().getDrawable(id)); + } + + /** + *

        Sets the animation style of the auto-complete drop-down list.

        + * + *

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

        + * + * @param animationStyle animation style to use when the drop-down appears + * and disappears. Set to -1 for the default animation, 0 for no + * animation, or a resource identifier for an explicit animation. + * + * @hide Pending API council approval + */ + public void setDropDownAnimationStyle(int animationStyle) { + mPopup.setAnimationStyle(animationStyle); + } + + /** + *

        Returns the animation style that is used when the drop-down list appears and disappears + *

        + * + * @return the animation style that is used when the drop-down list appears and disappears + * + * @hide Pending API council approval + */ + public int getDropDownAnimationStyle() { + return mPopup.getAnimationStyle(); + } + + /** + *

        Sets the vertical offset used for the auto-complete drop-down list.

        + * + * @param offset the vertical offset + * + * @hide Pending API council approval + */ + public void setDropDownVerticalOffset(int offset) { + mDropDownVerticalOffset = offset; + } + + /** + *

        Gets the vertical offset used for the auto-complete drop-down list.

        + * + * @return the vertical offset + * + * @hide Pending API council approval + */ + public int getDropDownVerticalOffset() { + return mDropDownVerticalOffset; + } + + /** + *

        Sets the horizontal offset used for the auto-complete drop-down list.

        + * + * @param offset the horizontal offset + * + * @hide Pending API council approval + */ + public void setDropDownHorizontalOffset(int offset) { + mDropDownHorizontalOffset = offset; + } + + /** + *

        Gets the horizontal offset used for the auto-complete drop-down list.

        + * + * @return the horizontal offset + * + * @hide Pending API council approval + */ + public int getDropDownHorizontalOffset() { + return mDropDownHorizontalOffset; + } + /** + * @return Whether the drop-down is visible as long as there is {@link #enoughToFilter()} + * + * @hide Pending API council approval + */ + public boolean isDropDownAlwaysVisible() { + return mDropDownAlwaysVisible; + } + + /** + * Sets whether the drop-down should remain visible as long as there is there is + * {@link #enoughToFilter()}. This is useful if an unknown number of results are expected + * to show up in the adapter sometime in the future. + * + * The drop-down will occupy the entire screen below {@link #getDropDownAnchor} regardless + * of the size or content of the list. {@link #getDropDownBackground()} will fill any space + * that is not used by the list. + * + * @param dropDownAlwaysVisible Whether to keep the drop-down visible. + * + * @hide Pending API council approval + */ + public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) { + mDropDownAlwaysVisible = dropDownAlwaysVisible; + } + + /** + * Checks whether the drop-down is dismissed when a suggestion is clicked. + * + * @hide Pending API council approval + */ + public boolean isDropDownDismissedOnCompletion() { + return mDropDownDismissedOnCompletion; + } + + /** + * Sets whether the drop-down is dismissed when a suggestion is clicked. This is + * true by default. + * + * @param dropDownDismissedOnCompletion Whether to dismiss the drop-down. + * + * @hide Pending API council approval + */ + public void setDropDownDismissedOnCompletion(boolean dropDownDismissedOnCompletion) { + mDropDownDismissedOnCompletion = dropDownDismissedOnCompletion; + } + /** *

        Returns the number of characters the user must type before the drop * down list is shown.

        @@ -628,16 +822,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } return ListView.INVALID_POSITION; } - - /** - * We're changing the adapter and its views so really, really clear everything out - * @hide - for SearchDialog only - */ - public void resetListAndClearViews() { - if (mDropDownList != null) { - mDropDownList.resetListAndClearViews(); - } - } /** *

        Starts filtering the content of the drop down list. The filtering @@ -709,7 +893,9 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } } - dismissDropDown(); + if (mDropDownDismissedOnCompletion) { + dismissDropDown(); + } } /** @@ -720,6 +906,42 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe return mBlockCompletion; } + /** + * Like {@link #setText(CharSequence)}, except that it can disable filtering. + * + * @param filter If false, no filtering will be performed + * as a result of this call. + * + * @hide Pending API council approval. + */ + public void setText(CharSequence text, boolean filter) { + if (filter) { + setText(text); + } else { + mBlockCompletion = true; + setText(text); + mBlockCompletion = false; + } + } + + /** + * Like {@link #setTextKeepState(CharSequence)}, except that it can disable filtering. + * + * @param filter If false, no filtering will be performed + * as a result of this call. + * + * @hide Pending API council approval. + */ + public void setTextKeepState(CharSequence text, boolean filter) { + if (filter) { + setTextKeepState(text); + } else { + mBlockCompletion = true; + setTextKeepState(text); + mBlockCompletion = false; + } + } + /** *

        Performs the text completion by replacing the current text by the * selected item. Subclasses should override this method to avoid replacing @@ -734,6 +956,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe Selection.setSelection(spannable, spannable.length()); } + /** {@inheritDoc} */ public void onFilterComplete(int count) { if (mAttachCount <= 0) return; @@ -744,7 +967,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * to filter. */ - if (count > 0 && enoughToFilter()) { + if ((count > 0 || mDropDownAlwaysVisible) && enoughToFilter()) { if (hasFocus() && hasWindowFocus()) { showDropDown(); } @@ -808,22 +1031,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe return result; } - /** - * Set the horizontal offset with respect to {@link #setDropDownAnchor(int)} - * @hide pending API council review - */ - public void setDropDownHorizontalOffset(int horizontalOffset) { - mDropDownHorizontalOffset = horizontalOffset; - } - - /** - * Set the vertical offset with respect to {@link #setDropDownAnchor(int)} - * @hide pending API council review - */ - public void setDropDownVerticalOffset(int verticalOffset) { - mDropDownVerticalOffset = verticalOffset; - } - /** *

        Used for lazy instantiation of the anchor view from the id we have. If the value of * the id is NO_ID or we can't find a view for the given id, we return this TextView as @@ -856,10 +1063,9 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe mDropDownVerticalOffset, widthSpec, height); } else { if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) { - mPopup.setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); + mPopup.setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, 0); } else { - mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT); + mPopup.setWindowLayoutMode(0, 0); if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { mPopup.setWidth(getDropDownAnchorView().getWidth()); } else { @@ -868,7 +1074,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } mPopup.setHeight(height); mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); - mPopup.setOutsideTouchable(true); + + // use outside touchable to dismiss drop down when touching outside of it, so + // only set this if the dropdown is not always visible + mPopup.setOutsideTouchable(!mDropDownAlwaysVisible); mPopup.setTouchInterceptor(new PopupTouchIntercepter()); mPopup.showAsDropDown(getDropDownAnchorView(), mDropDownHorizontalOffset, mDropDownVerticalOffset); @@ -962,12 +1171,19 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } } - // Max height available on the screen for a popup anchored to us - final int maxHeight = mPopup.getMaxAvailableHeight(this, mDropDownVerticalOffset); - //otherHeights += dropDownView.getPaddingTop() + dropDownView.getPaddingBottom(); + // Max height available on the screen for a popup. If this AutoCompleteTextView has + // the dropDownAlwaysVisible attribute, and the input method is not currently required, + // we then we ask for the height ignoring any bottom decorations like the input method. + // Otherwise we respect the input method. + boolean ignoreBottomDecorations = mDropDownAlwaysVisible && + mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; + final int maxHeight = mPopup.getMaxAvailableHeight( + getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations); - return mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED, + final int measuredHeight = mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED, 0, ListView.NO_POSITION, maxHeight - otherHeights, 2) + otherHeights; + + return mDropDownAlwaysVisible ? maxHeight : measuredHeight; } private View getHintView(Context context) { @@ -1044,7 +1260,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); - mPopup.update(); + showDropDown(); } return false; } @@ -1183,4 +1399,21 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe */ CharSequence fixText(CharSequence invalidText); } + + /** + * Allows us a private hook into the on click event without preventing users from setting + * their own click listener. + */ + private class PassThroughClickListener implements OnClickListener { + + private View.OnClickListener mWrapped; + + /** {@inheritDoc} */ + public void onClick(View v) { + onClickImpl(); + + if (mWrapped != null) mWrapped.onClick(v); + } + } + } diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index f5a0b1c09f1edfd0fe33925b9ed181f3eb4ed6a3..abcc715c77e58c60d128462510b209b009f0ede2 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -33,7 +33,7 @@ import com.android.internal.R; * something other than {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}. * */ -public abstract class CheckedTextView extends TextView implements Checkable { +public class CheckedTextView extends TextView implements Checkable { private boolean mChecked; private int mCheckMarkResource; private Drawable mCheckMarkDrawable; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 11fab8f96a22808443654f553fa1750f37dcc66c..9ec8347e4647987fa73004108cf0f9764987946b 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1534,14 +1534,14 @@ public class GridView extends AbsListView { case FOCUS_LEFT: if (selectedPosition > startOfRowPos) { mLayoutMode = LAYOUT_MOVE_SELECTION; - setSelectionInt(selectedPosition - 1); + setSelectionInt(Math.max(0, selectedPosition - 1)); moved = true; } break; case FOCUS_RIGHT: if (selectedPosition < endOfRowPos) { mLayoutMode = LAYOUT_MOVE_SELECTION; - setSelectionInt(selectedPosition + 1); + setSelectionInt(Math.min(selectedPosition + 1, mItemCount - 1)); moved = true; } break; diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 652e30c72133ff76798ec1724ab26f0573ff97b8..02fc7c6b8816068cb9a890b27b862f9f07a29869 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -283,7 +283,7 @@ public class HorizontalScrollView extends FrameLayout { final View child = getChildAt(0); int width = getMeasuredWidth(); - if (child.getMeasuredHeight() < width) { + if (child.getMeasuredWidth() < width) { final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, mPaddingTop diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index a786b3f940e3a3f1a9f4fa2841dc240343ee8e25..5472d6859c0abdf2ae82b8ddd90788ad55b670c4 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; +import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.graphics.drawable.ColorDrawable; import android.os.Parcel; @@ -113,7 +114,11 @@ public class ListView extends AbsListView { Drawable mDivider; int mDividerHeight; + + private boolean mIsCacheColorOpaque; + private boolean mDividerIsOpaque; private boolean mClipDivider; + private boolean mHeaderDividersEnabled; private boolean mFooterDividersEnabled; @@ -460,10 +465,30 @@ public class ListView extends AbsListView { */ @Override void resetList() { + // The parent's resetList() will remove all views from the layout so we need to + // cleanup the state of our footers and headers + clearRecycledState(mHeaderViewInfos); + clearRecycledState(mFooterViewInfos); + super.resetList(); + mLayoutMode = LAYOUT_NORMAL; } + private void clearRecycledState(ArrayList infos) { + if (infos != null) { + final int count = infos.size(); + + for (int i = 0; i < count; i++) { + final View child = infos.get(i).view; + final LayoutParams p = (LayoutParams) child.getLayoutParams(); + if (p != null) { + p.recycledHeaderFooter = false; + } + } + } + } + /** * @return Whether the list needs to show the top fading edge */ @@ -1394,6 +1419,11 @@ public class ListView extends AbsListView { resetList(); invokeOnItemScrollListener(); return; + } else if (mItemCount != mAdapter.getCount()) { + throw new IllegalStateException("The content of the adapter has changed but " + + "ListView did not receive a notification. Make sure the content of " + + "your adapter is not modified from a background thread, but only " + + "from the UI thread."); } setSelectedPositionInt(mNextSelectedPosition); @@ -2751,6 +2781,20 @@ public class ListView extends AbsListView { return mItemsCanFocus; } + /** + * @hide Pending API council approval. + */ + @Override + public boolean isOpaque() { + return (mCachingStarted && mIsCacheColorOpaque && mDividerIsOpaque) || super.isOpaque(); + } + + @Override + public void setCacheColorHint(int color) { + mIsCacheColorOpaque = (color >>> 24) == 0xFF; + super.setCacheColorHint(color); + } + @Override protected void dispatchDraw(Canvas canvas) { // Draw the dividers @@ -2872,6 +2916,7 @@ public class ListView extends AbsListView { mClipDivider = false; } mDivider = divider; + mDividerIsOpaque = divider == null || divider.getOpacity() == PixelFormat.OPAQUE; requestLayoutIfNecessary(); } @@ -3214,6 +3259,29 @@ public class ListView extends AbsListView { return null; } + /** + * Returns the set of checked items ids. The result is only valid if + * the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}. + * + * @return A new array which contains the id of each checked item in the list. + */ + public long[] getCheckItemIds() { + if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null && mAdapter != null) { + final SparseBooleanArray states = mCheckStates; + final int count = states.size(); + final long[] ids = new long[count]; + final ListAdapter adapter = mAdapter; + + for (int i = 0; i < count; i++) { + ids[i]= adapter.getItemId(states.keyAt(i)); + } + + return ids; + } + + return new long[0]; + } + /** * Clear any choices previously set */ diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index b162a0eba1f4aad62013cf6263de48e2808b7f2d..0c9d980488eaff443a010b65d7fa29876ac8626f 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -444,27 +444,55 @@ public class MediaController extends FrameLayout { updatePausePlay(); } + // There are two scenarios that can trigger the seekbar listener to trigger: + // + // The first is the user using the touchpad to adjust the posititon of the + // seekbar's thumb. In this case onStartTrackingTouch is called followed by + // a number of onProgressChanged notifications, concluded by onStopTrackingTouch. + // We're setting the field "mDragging" to true for the duration of the dragging + // session to avoid jumps in the position in case of ongoing playback. + // + // The second scenario involves the user operating the scroll ball, in this + // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications, + // we will simply apply the updated position without suspending regular updates. private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { - long duration; public void onStartTrackingTouch(SeekBar bar) { show(3600000); - duration = mPlayer.getDuration(); - } - public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) { - if (fromtouch) { - mDragging = true; - duration = mPlayer.getDuration(); - long newposition = (duration * progress) / 1000L; - mPlayer.seekTo( (int) newposition); - if (mCurrentTime != null) - mCurrentTime.setText(stringForTime( (int) newposition)); + + mDragging = true; + + // By removing these pending progress messages we make sure + // that a) we won't update the progress while the user adjusts + // the seekbar and b) once the user is done dragging the thumb + // we will post one of these messages to the queue again and + // this ensures that there will be exactly one message queued up. + mHandler.removeMessages(SHOW_PROGRESS); + } + + public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { + if (!fromuser) { + // We're not interested in programmatically generated changes to + // the progress bar's position. + return; } + + long duration = mPlayer.getDuration(); + long newposition = (duration * progress) / 1000L; + mPlayer.seekTo( (int) newposition); + if (mCurrentTime != null) + mCurrentTime.setText(stringForTime( (int) newposition)); } + public void onStopTrackingTouch(SeekBar bar) { mDragging = false; setProgress(); updatePausePlay(); show(sDefaultTimeout); + + // Ensure that progress is properly updated in the future, + // the call to show() does not guarantee this because it is a + // no-op if we are already showing. + mHandler.sendEmptyMessage(SHOW_PROGRESS); } }; diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 2c9714e318ba3d87f60f3ad81e009079f6d35c0f..78c7bd8e54c4bc0ec3c1b2664f935b08a23a2287 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -25,6 +25,7 @@ import android.view.WindowManager; import android.view.Gravity; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.view.WindowManagerImpl; import android.view.ViewTreeObserver.OnScrollChangedListener; import android.view.View.OnTouchListener; import android.graphics.PixelFormat; @@ -72,8 +73,8 @@ public class PopupWindow { */ public static final int INPUT_METHOD_NOT_NEEDED = 2; - private final Context mContext; - private final WindowManager mWindowManager; + private Context mContext; + private WindowManager mWindowManager; private boolean mIsShowing; private boolean mIsDropdown; @@ -158,8 +159,7 @@ public class PopupWindow { */ public PopupWindow(Context context, AttributeSet attrs, int defStyle) { mContext = context; - mWindowManager = (WindowManager)context.getSystemService( - Context.WINDOW_SERVICE); + mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); TypedArray a = context.obtainStyledAttributes( @@ -272,11 +272,11 @@ public class PopupWindow { * @param height the popup's height * @param focusable true if the popup can be focused, false otherwise */ - public PopupWindow(View contentView, int width, int height, - boolean focusable) { - mContext = contentView.getContext(); - mWindowManager = (WindowManager)mContext.getSystemService( - Context.WINDOW_SERVICE); + public PopupWindow(View contentView, int width, int height, boolean focusable) { + if (contentView != null) { + mContext = contentView.getContext(); + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + } setContentView(contentView); setWidth(width); setHeight(height); @@ -373,6 +373,14 @@ public class PopupWindow { } mContentView = contentView; + + if (mContext == null) { + mContext = mContentView.getContext(); + } + + if (mWindowManager == null) { + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + } } /** @@ -747,6 +755,11 @@ public class PopupWindow { * @param p the layout parameters of the popup's content view */ private void preparePopup(WindowManager.LayoutParams p) { + if (mContentView == null || mContext == null || mWindowManager == null) { + throw new IllegalStateException("You must specify a valid content view by " + + "calling setContentView() before attempting to show the popup."); + } + if (mBackground != null) { final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams(); int height = ViewGroup.LayoutParams.FILL_PARENT; @@ -948,14 +961,38 @@ public class PopupWindow { * shown. */ public int getMaxAvailableHeight(View anchor, int yOffset) { + return getMaxAvailableHeight(anchor, yOffset, false); + } + + /** + * Returns the maximum height that is available for the popup to be + * completely shown, optionally ignoring any bottom decorations such as + * the input method. It is recommended that this height be the maximum for + * the popup's height, otherwise it is possible that the popup will be + * clipped. + * + * @param anchor The view on which the popup window must be anchored. + * @param yOffset y offset from the view's bottom edge + * @param ignoreBottomDecorations if true, the height returned will be + * all the way to the bottom of the display, ignoring any + * bottom decorations + * @return The maximum available height for the popup to be completely + * shown. + * + * @hide Pending API council approval. + */ + public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) { final Rect displayFrame = new Rect(); anchor.getWindowVisibleDisplayFrame(displayFrame); final int[] anchorPos = mDrawingLocation; anchor.getLocationOnScreen(anchorPos); - final int distanceToBottom = displayFrame.bottom - - (anchorPos[1] + anchor.getHeight()) - yOffset; + int bottomEdge = displayFrame.bottom; + if (ignoreBottomDecorations) { + bottomEdge = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight(); + } + final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset; final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset; // anchorPos[1] is distance from anchor to top of screen @@ -1116,7 +1153,7 @@ public class PopupWindow { p.flags = newFlags; update = true; } - + if (update) { mWindowManager.updateViewLayout(mPopupView, p); } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index c4f0abdd85a6ef4fa7bf63100c680e9274edcb80..edbb3db255abb06759fa278280509168e54d8932 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -823,7 +823,7 @@ public class RelativeLayout extends ViewGroup { @ViewDebug.IntToString(from = RIGHT_OF, to = "rightOf") }, mapping = { @ViewDebug.IntToString(from = TRUE, to = "true"), - @ViewDebug.IntToString(from = 0, to = "NO_ID") + @ViewDebug.IntToString(from = 0, to = "FALSE/NO_ID") }) private int[] mRules = new int[VERB_COUNT]; diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java index 093c24e0ca58e84d4af59a283ee37a4d8d3c7e87..9dd4d151df1a6db6ae3c2e53cc8fcd15b4b5c58f 100644 --- a/core/java/android/widget/SimpleAdapter.java +++ b/core/java/android/widget/SimpleAdapter.java @@ -25,6 +25,7 @@ import android.net.Uri; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; /** * An easy adapter to map static data to views defined in an XML file. You can specify the data @@ -57,6 +58,7 @@ public class SimpleAdapter extends BaseAdapter implements Filterable { private int mResource; private int mDropDownResource; private LayoutInflater mInflater; + private final WeakHashMap mHolders = new WeakHashMap(); private SimpleFilter mFilter; private ArrayList> mUnfilteredData; @@ -128,7 +130,7 @@ public class SimpleAdapter extends BaseAdapter implements Filterable { holder[i] = v.findViewById(to[i]); } - v.setTag(holder); + mHolders.put(v, holder); } else { v = convertView; } @@ -160,7 +162,7 @@ public class SimpleAdapter extends BaseAdapter implements Filterable { } final ViewBinder binder = mViewBinder; - final View[] holder = (View[]) view.getTag(); + final View[] holder = mHolders.get(view); final String[] from = mFrom; final int[] to = mTo; final int count = to.length; diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java index c1595eaf8ac605eb568731e3b32c097f99842e6d..b6a49e5bd5f794ccb28eaa482bb8550461253948 100644 --- a/core/java/android/widget/SimpleCursorAdapter.java +++ b/core/java/android/widget/SimpleCursorAdapter.java @@ -22,6 +22,8 @@ import android.net.Uri; import android.view.View; import android.view.ViewGroup; +import java.util.WeakHashMap; + /** * An easy adapter to map columns from a cursor to TextViews or ImageViews * defined in an XML file. You can specify which columns you want, which @@ -64,6 +66,7 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter { private CursorToStringConverter mCursorToStringConverter; private ViewBinder mViewBinder; private String[] mOriginalFrom; + private final WeakHashMap mHolders = new WeakHashMap(); /** * Constructor. @@ -106,7 +109,7 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter { for (int i = 0; i < count; i++) { holder[i] = v.findViewById(to[i]); } - v.setTag(holder); + mHolders.put(v, holder); return v; } @@ -137,7 +140,7 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter { */ @Override public void bindView(View view, Context context, Cursor cursor) { - final View[] holder = (View[]) view.getTag(); + final View[] holder = mHolders.get(view); final ViewBinder binder = mViewBinder; final int count = mTo.length; final int[] from = mFrom; @@ -145,17 +148,17 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter { for (int i = 0; i < count; i++) { final View v = holder[i]; if (v != null) { - String text = cursor.getString(from[i]); - if (text == null) { - text = ""; - } - boolean bound = false; if (binder != null) { bound = binder.setViewValue(v, cursor, from[i]); } if (!bound) { + String text = cursor.getString(from[i]); + if (text == null) { + text = ""; + } + if (v instanceof TextView) { setViewText((TextView) v, text); } else if (v instanceof ImageView) { diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java index e0f1bb41ce892534c1c045c5c5c8107483faf71d..92561edc1cd119dff6afaaa9188c16abc359541a 100644 --- a/core/java/android/widget/SlidingDrawer.java +++ b/core/java/android/widget/SlidingDrawer.java @@ -206,10 +206,15 @@ public class SlidingDrawer extends ViewGroup { int contentId = a.getResourceId(R.styleable.SlidingDrawer_content, 0); if (contentId == 0) { - throw new IllegalArgumentException("The handle attribute is required and must refer " + throw new IllegalArgumentException("The content attribute is required and must refer " + "to a valid child."); } + if (handleId == contentId) { + throw new IllegalArgumentException("The content and handle attributes must refer " + + "to different children."); + } + mHandleId = handleId; mContentId = contentId; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9c810e1c426de0af48bbf488f374c71525c597ca..adfc74fbfae26a098b24f825bfdf5a503d10353d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1641,6 +1641,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @android.view.RemotableViewMethod public void setTextScaleX(float size) { if (size != mTextPaint.getTextScaleX()) { + mUserSetTextScaleX = true; mTextPaint.setTextScaleX(size); if (mLayout != null) { @@ -2511,6 +2512,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener text = ""; } + if (!mUserSetTextScaleX) mTextPaint.setTextScaleX(1.0f); + if (text instanceof Spanned && ((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) { setHorizontalFadingEdgeEnabled(true); @@ -3920,6 +3923,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener layout.draw(canvas, highlight, mHighlightPaint, voffsetCursor - voffsetText); + if (mMarquee != null && mMarquee.shouldDrawGhost()) { + canvas.translate((int) mMarquee.getGhostOffset(), 0.0f); + layout.draw(canvas, highlight, mHighlightPaint, voffsetCursor - voffsetText); + } + /* Comment out until we decide what to do about animations if (currentTransformation != null) { mTextPaint.setLinearTextOn(isLinearTextOn); @@ -4426,29 +4434,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener boolean reportExtractedText() { final InputMethodState ims = mInputMethodState; - final boolean contentChanged = ims.mContentChanged; - if (ims != null && (contentChanged || ims.mSelectionModeChanged)) { - ims.mContentChanged = false; - ims.mSelectionModeChanged = false; - final ExtractedTextRequest req = mInputMethodState.mExtracting; - if (req != null) { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - if (DEBUG_EXTRACT) Log.v(TAG, "Retrieving extracted start=" - + ims.mChangedStart + " end=" + ims.mChangedEnd - + " delta=" + ims.mChangedDelta); - if (ims.mChangedStart < 0 && !contentChanged) { - ims.mChangedStart = EXTRACT_NOTHING; - } - if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd, - ims.mChangedDelta, ims.mTmpExtracted)) { - if (DEBUG_EXTRACT) Log.v(TAG, "Reporting extracted start=" - + ims.mTmpExtracted.partialStartOffset - + " end=" + ims.mTmpExtracted.partialEndOffset - + ": " + ims.mTmpExtracted.text); - imm.updateExtractedText(this, req.token, - mInputMethodState.mTmpExtracted); - return true; + if (ims != null) { + final boolean contentChanged = ims.mContentChanged; + if (contentChanged || ims.mSelectionModeChanged) { + ims.mContentChanged = false; + ims.mSelectionModeChanged = false; + final ExtractedTextRequest req = mInputMethodState.mExtracting; + if (req != null) { + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + if (DEBUG_EXTRACT) Log.v(TAG, "Retrieving extracted start=" + + ims.mChangedStart + " end=" + ims.mChangedEnd + + " delta=" + ims.mChangedDelta); + if (ims.mChangedStart < 0 && !contentChanged) { + ims.mChangedStart = EXTRACT_NOTHING; + } + if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd, + ims.mChangedDelta, ims.mTmpExtracted)) { + if (DEBUG_EXTRACT) Log.v(TAG, "Reporting extracted start=" + + ims.mTmpExtracted.partialStartOffset + + " end=" + ims.mTmpExtracted.partialEndOffset + + ": " + ims.mTmpExtracted.text); + imm.updateExtractedText(this, req.token, + mInputMethodState.mTmpExtracted); + return true; + } } } } @@ -4814,16 +4824,38 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } 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; + if (!compressText(ellipsisWidth)) { + 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 boolean compressText(float width) { + // Only compress the text if it hasn't been compressed by the previous pass + if (width > 0.0f && mLayout != null && getLineCount() == 1 && !mUserSetTextScaleX && + mTextPaint.getTextScaleX() == 1.0f) { + final float textWidth = mLayout.getLineWidth(0); + final float overflow = (textWidth + 1.0f - width) / width; + if (overflow > 0.0f && overflow <= Marquee.MARQUEE_DELTA_MAX) { + mTextPaint.setTextScaleX(1.0f - overflow - 0.005f); + post(new Runnable() { + public void run() { + requestLayout(); + } + }); + return true; } } + + return false; } private static int desired(Layout layout) { @@ -5683,8 +5715,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void startMarquee() { + if (compressText(getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight())) { + return; + } + if ((mMarquee == null || mMarquee.isStopped()) && (isFocused() || isSelected()) && getLineCount() == 1 && canMarquee()) { + if (mMarquee == null) mMarquee = new Marquee(this); mMarquee.start(mMarqueeRepeatLimit); } @@ -5708,6 +5745,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private static final class Marquee extends Handler { // TODO: Add an option to configure this + private static final float MARQUEE_DELTA_MAX = 0.07f; private static final int MARQUEE_DELAY = 1200; private static final int MARQUEE_RESTART_DELAY = 1200; private static final int MARQUEE_RESOLUTION = 1000 / 30; @@ -5726,6 +5764,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private byte mStatus = MARQUEE_STOPPED; private float mScrollUnit; private float mMaxScroll; + float mMaxFadeScroll; + private float mGhostStart; + private float mGhostOffset; + private float mFadeStop; private int mRepeatLimit; float mScroll; @@ -5801,13 +5843,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (textView != null && textView.mLayout != null) { mStatus = MARQUEE_STARTING; mScroll = 0.0f; - mMaxScroll = textView.mLayout.getLineWidth(0) - (textView.getWidth() - - textView.getCompoundPaddingLeft() - textView.getCompoundPaddingRight()); + final int textWidth = textView.getWidth() - textView.getCompoundPaddingLeft() - + textView.getCompoundPaddingRight(); + final float lineWidth = textView.mLayout.getLineWidth(0); + final float gap = textWidth / 3.0f; + mGhostStart = lineWidth - textWidth + gap; + mMaxScroll = mGhostStart + textWidth; + mGhostOffset = lineWidth + gap; + mFadeStop = lineWidth + textWidth / 6.0f; + mMaxFadeScroll = mGhostStart + lineWidth + lineWidth; + textView.invalidate(); sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY); } } + float getGhostOffset() { + return mGhostOffset; + } + + boolean shouldDrawLeftFade() { + return mScroll <= mFadeStop; + } + + boolean shouldDrawGhost() { + return mStatus == MARQUEE_RUNNING && mScroll > mGhostStart; + } + boolean isRunning() { return mStatus == MARQUEE_RUNNING; } @@ -6433,7 +6495,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { if (mMarquee != null && !mMarquee.isStopped()) { final Marquee marquee = mMarquee; - return marquee.mScroll / getHorizontalFadingEdgeLength(); + if (marquee.shouldDrawLeftFade()) { + return marquee.mScroll / getHorizontalFadingEdgeLength(); + } else { + return 0.0f; + } } else if (getLineCount() == 1) { switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: @@ -6455,7 +6521,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { if (mMarquee != null && !mMarquee.isStopped()) { final Marquee marquee = mMarquee; - return (marquee.mMaxScroll - marquee.mScroll) / getHorizontalFadingEdgeLength(); + return (marquee.mMaxFadeScroll - marquee.mScroll) / getHorizontalFadingEdgeLength(); } else if (getLineCount() == 1) { switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: @@ -6994,7 +7060,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private ArrayList mListeners = null; // display attributes - private TextPaint mTextPaint; + private TextPaint mTextPaint; + private boolean mUserSetTextScaleX; private Paint mHighlightPaint; private int mHighlightColor = 0xFFBBDDFF; private Layout mLayout; diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index bb0c9120cef60a41ecd4dad31e174057b3e695c1..e1ff2a52062ff25d80505b69b3cec41c193b1715 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -45,7 +45,10 @@ interface IBatteryStats { void noteFullWifiLockReleased(int uid); void noteScanWifiLockAcquired(int uid); void noteScanWifiLockReleased(int uid); + void noteWifiMulticastEnabled(int uid); + void noteWifiMulticastDisabled(int uid); void setOnBattery(boolean onBattery, int level); + void recordCurrentLevel(int level); long getAwakeTimeBattery(); long getAwakeTimePlugged(); } diff --git a/core/java/com/android/internal/app/IUsageStats.aidl b/core/java/com/android/internal/app/IUsageStats.aidl index 6b053d5c99751557e4738d5e171462f8aa32add9..1ea74090a419e1f9d5e3934c1a83bfafd363888c 100755 --- a/core/java/com/android/internal/app/IUsageStats.aidl +++ b/core/java/com/android/internal/app/IUsageStats.aidl @@ -22,6 +22,7 @@ import com.android.internal.os.PkgUsageStats; interface IUsageStats { void noteResumeComponent(in ComponentName componentName); void notePauseComponent(in ComponentName componentName); + void noteLaunchTime(in ComponentName componentName, int millis); PkgUsageStats getPkgUsageStats(in ComponentName componentName); PkgUsageStats[] getAllPkgUsageStats(); } diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java new file mode 100644 index 0000000000000000000000000000000000000000..77d6e20a0fa5161b5cfaaf2e1fe4e8a2f42bf52b --- /dev/null +++ b/core/java/com/android/internal/app/ShutdownThread.java @@ -0,0 +1,241 @@ +/* + * 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.app; + +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.ProgressDialog; +import android.app.AlertDialog; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Handler; +import android.os.RemoteException; +import android.os.Power; +import android.os.ServiceManager; +import android.os.SystemClock; +import com.android.internal.telephony.ITelephony; +import android.util.Log; +import android.view.WindowManager; + +public final class ShutdownThread extends Thread { + // constants + private static final String TAG = "ShutdownThread"; + private static final int MAX_NUM_PHONE_STATE_READS = 16; + private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; + // maximum time we wait for the shutdown broadcast before going on. + private static final int MAX_BROADCAST_TIME = 10*1000; + + // state tracking + private static Object sIsStartedGuard = new Object(); + private static boolean sIsStarted = false; + + // static instance of this thread + private static final ShutdownThread sInstance = new ShutdownThread(); + + private final Object mBroadcastDoneSync = new Object(); + private boolean mBroadcastDone; + private Context mContext; + private Handler mHandler; + + private ShutdownThread() { + } + + /** + * Request a clean shutdown, waiting for subsystems to clean up their + * state etc. Must be called from a Looper thread in which its UI + * is shown. + * + * @param context Context used to display the shutdown progress dialog. + */ + public static void shutdown(final Context context, boolean confirm) { + // ensure that only one thread is trying to power down. + // any additional calls are just returned + synchronized (sIsStartedGuard){ + if (sIsStarted) { + Log.d(TAG, "Request to shutdown already running, returning."); + return; + } + } + + Log.d(TAG, "Notifying thread to start radio shutdown"); + + if (confirm) { + final AlertDialog dialog = new AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(com.android.internal.R.string.power_off) + .setMessage(com.android.internal.R.string.shutdown_confirm) + .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + beginShutdownSequence(context); + } + }) + .setNegativeButton(com.android.internal.R.string.no, null) + .create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } else { + beginShutdownSequence(context); + } + } + + private static void beginShutdownSequence(Context context) { + synchronized (sIsStartedGuard) { + sIsStarted = true; + } + + // throw up an indeterminate system dialog to indicate radio is + // shutting down. + ProgressDialog pd = new ProgressDialog(context); + pd.setTitle(context.getText(com.android.internal.R.string.power_off)); + pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); + pd.setIndeterminate(true); + pd.setCancelable(false); + pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + + pd.show(); + + // start the thread that initiates shutdown + sInstance.mContext = context; + sInstance.mHandler = new Handler() { + }; + sInstance.start(); + } + + void broadcastDone() { + synchronized (mBroadcastDoneSync) { + mBroadcastDone = true; + mBroadcastDoneSync.notifyAll(); + } + } + + /** + * Makes sure we handle the shutdown gracefully. + * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. + */ + public void run() { + boolean bluetoothOff; + boolean radioOff; + + BroadcastReceiver br = new BroadcastReceiver() { + @Override public void onReceive(Context context, Intent intent) { + // We don't allow apps to cancel this, so ignore the result. + broadcastDone(); + } + }; + + Log.i(TAG, "Sending shutdown broadcast..."); + + // First send the high-level shut down broadcast. + mBroadcastDone = false; + mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null, + br, mHandler, 0, null, null); + + final long endTime = System.currentTimeMillis() + MAX_BROADCAST_TIME; + synchronized (mBroadcastDoneSync) { + while (!mBroadcastDone) { + long delay = endTime - System.currentTimeMillis(); + if (delay <= 0) { + Log.w(TAG, "Shutdown broadcast timed out"); + break; + } + try { + mBroadcastDoneSync.wait(delay); + } catch (InterruptedException e) { + } + } + } + + Log.i(TAG, "Shutting down activity manager..."); + + final IActivityManager am = + ActivityManagerNative.asInterface(ServiceManager.checkService("activity")); + if (am != null) { + try { + am.shutdown(MAX_BROADCAST_TIME); + } catch (RemoteException e) { + } + } + + final ITelephony phone = + ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); + final IBluetoothDevice bluetooth = + IBluetoothDevice.Stub.asInterface(ServiceManager.checkService( + Context.BLUETOOTH_SERVICE)); + + try { + bluetoothOff = bluetooth == null || + bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; + if (!bluetoothOff) { + Log.w(TAG, "Disabling Bluetooth..."); + bluetooth.disable(false); // disable but don't persist new state + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during bluetooth shutdown", ex); + bluetoothOff = true; + } + + try { + radioOff = phone == null || !phone.isRadioOn(); + if (!radioOff) { + Log.w(TAG, "Turning off radio..."); + phone.setRadio(false); + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during radio shutdown", ex); + radioOff = true; + } + + Log.i(TAG, "Waiting for Bluetooth and Radio..."); + + // Wait a max of 32 seconds for clean shutdown + for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) { + if (!bluetoothOff) { + try { + bluetoothOff = + bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during bluetooth shutdown", ex); + bluetoothOff = true; + } + } + if (!radioOff) { + try { + radioOff = !phone.isRadioOn(); + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during radio shutdown", ex); + radioOff = true; + } + } + if (radioOff && bluetoothOff) { + Log.i(TAG, "Radio and Bluetooth shutdown complete."); + break; + } + SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); + } + + //shutdown power + Log.i(TAG, "Performing low-level shutdown..."); + Power.shutdown(); + } +} diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl new file mode 100644 index 0000000000000000000000000000000000000000..ce39768137e28eab28b7eaa9b8bab5e3c9850ff0 --- /dev/null +++ b/core/java/com/android/internal/backup/IBackupTransport.aidl @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.backup; + +import android.os.ParcelFileDescriptor; + +/** {@hide} */ +interface IBackupTransport { +/* STOPSHIP - don't ship with this comment in place + Things the transport interface has to do: + 1. set up the connection to the destination + - set up encryption + - for Google cloud, log in using the user's gaia credential or whatever + - for sd, spin off the backup transport and establish communication with it + 2. send each app's backup transaction + - parse the data file for key/value pointers etc + - send key/blobsize set to the Google cloud, get back quota ok/rejected response + - sd/adb doesn't preflight; no per-app quota + - app's entire change is essentially atomic + - cloud transaction encrypts then sends each key/value pair separately; we already + parsed the data when preflighting so we don't have to again here + - sd target streams raw data into encryption envelope then to sd? + 3. shut down connection to destination + - cloud: tear down connection etc + - sd: close the file and shut down the writer proxy +*/ + /** + * Establish a connection to the back-end data repository, if necessary. If the transport + * needs to initialize state that is not tied to individual applications' backup operations, + * this is where it should be done. + * + * @return Zero on success; a nonzero error code on failure. + */ + int startSession(); + + /** + * Send one application's data to the backup destination. + * + * @param packageName The identity of the application whose data is being backed up. + * @param data The data stream that resulted from invoking the application's + * BackupService.doBackup() method. This may be a pipe rather than a + * file on persistent media, so it may not be seekable. + * @return Zero on success; a nonzero error code on failure. + */ + int performBackup(String packageName, in ParcelFileDescriptor data); + + /** + * Terminate the backup session, closing files, freeing memory, and cleaning up whatever + * other state the transport required. + * + * @return Zero on success; a nonzero error code on failure. Even on failure, the session + * is torn down and must be restarted if another backup is attempted. + */ + int endSession(); +} diff --git a/core/java/com/android/internal/os/AtomicFile.java b/core/java/com/android/internal/os/AtomicFile.java new file mode 100644 index 0000000000000000000000000000000000000000..ca0345f4870d6389529b6048f12afb07a3baf885 --- /dev/null +++ b/core/java/com/android/internal/os/AtomicFile.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.os.FileUtils; +import android.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Helper class for performing atomic operations on a file, by creating a + * backup file until a write has successfully completed. + */ +public class AtomicFile { + private final File mBaseName; + private final File mBackupName; + + public AtomicFile(File baseName) { + mBaseName = baseName; + mBackupName = new File(baseName.getPath() + ".bak"); + } + + public File getBaseFile() { + return mBaseName; + } + + public FileOutputStream startWrite() throws IOException { + // Rename the current file so it may be used as a backup during the next read + if (mBaseName.exists()) { + if (!mBaseName.renameTo(mBackupName)) { + mBackupName.delete(); + if (!mBaseName.renameTo(mBackupName)) { + Log.w("AtomicFile", "Couldn't rename file " + mBaseName + + " to backup file " + mBackupName); + } + } + } + FileOutputStream str = null; + try { + str = new FileOutputStream(mBaseName); + } catch (FileNotFoundException e) { + File parent = mBaseName.getParentFile(); + if (!parent.mkdir()) { + throw new IOException("Couldn't create directory " + mBaseName); + } + FileUtils.setPermissions( + parent.getPath(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, + -1, -1); + try { + str = new FileOutputStream(mBaseName); + } catch (FileNotFoundException e2) { + throw new IOException("Couldn't create " + mBaseName); + } + } + return str; + } + + public void finishWrite(FileOutputStream str) { + if (str != null) { + try { + str.close(); + mBackupName.delete(); + } catch (IOException e) { + Log.w("AtomicFile", "finishWrite: Got exception:", e); + } + } + } + + public void failWrite(FileOutputStream str) { + if (str != null) { + try { + str.close(); + mBaseName.delete(); + mBackupName.renameTo(mBaseName); + } catch (IOException e) { + Log.w("AtomicFile", "failWrite: Got exception:", e); + } + } + } + + public FileOutputStream openAppend() throws IOException { + try { + return new FileOutputStream(mBaseName, true); + } catch (FileNotFoundException e) { + throw new IOException("Couldn't append " + mBaseName); + } + } + + public void truncate() throws IOException { + try { + FileOutputStream fos = new FileOutputStream(mBaseName); + fos.close(); + } catch (FileNotFoundException e) { + throw new IOException("Couldn't append " + mBaseName); + } catch (IOException e) { + } + } + + public FileInputStream openRead() throws FileNotFoundException { + if (mBackupName.exists()) { + mBaseName.delete(); + mBackupName.renameTo(mBaseName); + } + return new FileInputStream(mBaseName); + } + + public byte[] readFully() throws IOException { + FileInputStream stream = openRead(); + try { + 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; + } + } + } finally { + stream.close(); + } + } +} diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 808508042997d3411523e4534c3c9b1d38513014..e8356a2c641518106cbf10c67c224ebd33bd0023 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -21,9 +21,11 @@ import android.os.NetStat; import android.os.Parcel; import android.os.ParcelFormatException; import android.os.Parcelable; +import android.os.Process; import android.os.SystemClock; import android.telephony.TelephonyManager; import android.util.Log; +import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.SparseArray; @@ -31,9 +33,13 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.Map; +import java.util.Set; /** * All information we are collecting about things that can happen that impact @@ -48,7 +54,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 32; + private static final int VERSION = 34; private final File mFile; private final File mBackupFile; @@ -63,11 +69,11 @@ public final class BatteryStatsImpl extends BatteryStats { // 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 SparseArray> mSensorTimers - = new SparseArray>(); + final ArrayList mPartialTimers = new ArrayList(); + final ArrayList mFullTimers = new ArrayList(); + final ArrayList mWindowTimers = new ArrayList(); + final SparseArray> mSensorTimers + = new SparseArray>(); // These are the objects that will want to do something when the device // is unplugged from power. @@ -88,31 +94,33 @@ public final class BatteryStatsImpl extends BatteryStats { long mLastRealtime; boolean mScreenOn; - Timer mScreenOnTimer; + StopwatchTimer mScreenOnTimer; int mScreenBrightnessBin = -1; - final Timer[] mScreenBrightnessTimer = new Timer[NUM_SCREEN_BRIGHTNESS_BINS]; + final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; Counter mInputEventCounter; boolean mPhoneOn; - Timer mPhoneOnTimer; + StopwatchTimer mPhoneOnTimer; int mPhoneSignalStrengthBin = -1; - final Timer[] mPhoneSignalStrengthsTimer = new Timer[NUM_SIGNAL_STRENGTH_BINS]; + final StopwatchTimer[] mPhoneSignalStrengthsTimer = + new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS]; int mPhoneDataConnectionType = -1; - final Timer[] mPhoneDataConnectionsTimer = new Timer[NUM_DATA_CONNECTION_TYPES]; + final StopwatchTimer[] mPhoneDataConnectionsTimer = + new StopwatchTimer[NUM_DATA_CONNECTION_TYPES]; boolean mWifiOn; - Timer mWifiOnTimer; + StopwatchTimer mWifiOnTimer; int mWifiOnUid = -1; boolean mWifiRunning; - Timer mWifiRunningTimer; + StopwatchTimer mWifiRunningTimer; boolean mBluetoothOn; - Timer mBluetoothOnTimer; + StopwatchTimer mBluetoothOnTimer; /** * These provide time bases that discount the time the device is plugged @@ -131,10 +139,41 @@ public final class BatteryStatsImpl extends BatteryStats { /* * These keep track of battery levels (1-100) at the last plug event and the last unplug event. */ - int mUnpluggedStartLevel; - int mPluggedStartLevel; + int mDischargeStartLevel; + int mDischargeCurrentLevel; long mLastWriteTime = 0; // Milliseconds + + /* + * Holds a SamplingTimer associated with each kernel wakelock name being tracked. + */ + private final HashMap mKernelWakelockStats = + new HashMap(); + + public Map getKernelWakelockStats() { + return mKernelWakelockStats; + } + + private static int sKernelWakelockUpdateVersion = 0; + + private static final int[] PROC_WAKELOCKS_FORMAT = new int[] { + Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name + Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime + }; + + private final String[] mProcWakelocksName = new String[3]; + private final long[] mProcWakelocksData = new long[3]; + + /* + * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added + * to mKernelWakelockStats. + */ + private final Map mProcWakelockFileStats = + new HashMap(); // For debugging public BatteryStatsImpl() { @@ -200,7 +239,7 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public int getCount(int which) { + public int getCountLocked(int which) { int val; if (which == STATS_LAST) { val = mLastCount; @@ -242,11 +281,9 @@ public final class BatteryStatsImpl extends BatteryStats { /** * State for keeping track of timing information. */ - public static final class Timer extends BatteryStats.Timer implements Unpluggable { + public static abstract class Timer extends BatteryStats.Timer implements Unpluggable { final int mType; - final ArrayList mTimerPool; - - int mNesting; + int mCount; int mLoadedCount; @@ -281,24 +318,10 @@ public final class BatteryStatsImpl extends BatteryStats { * power. */ long mUnpluggedTime; - - /** - * The last time at which we updated the timer. If mNesting is > 0, - * subtract this from the current battery time to find the amount of - * time we have been running since we last computed an update. - */ - long mUpdateTime; - - /** - * The total time at which the timer was acquired, to determine if - * was actually held for an interesting duration. - */ - long mAcquireTime; - Timer(int type, ArrayList timerPool, - ArrayList unpluggables, Parcel in) { + Timer(int type, ArrayList unpluggables, Parcel in) { mType = type; - mTimerPool = timerPool; + mCount = in.readInt(); mLoadedCount = in.readInt(); mLastCount = in.readInt(); @@ -306,17 +329,19 @@ public final class BatteryStatsImpl extends BatteryStats { mTotalTime = in.readLong(); mLoadedTime = in.readLong(); mLastTime = in.readLong(); - mUpdateTime = in.readLong(); mUnpluggedTime = in.readLong(); unpluggables.add(this); } - Timer(int type, ArrayList timerPool, - ArrayList unpluggables) { + Timer(int type, ArrayList unpluggables) { mType = type; - mTimerPool = timerPool; unpluggables.add(this); } + + protected abstract long computeRunTimeLocked(long curBatteryRealtime); + + protected abstract int computeCurrentCountLocked(); + public void writeToParcel(Parcel out, long batteryRealtime) { out.writeInt(mCount); @@ -326,7 +351,6 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(computeRunTimeLocked(batteryRealtime)); out.writeLong(mLoadedTime); out.writeLong(mLastTime); - out.writeLong(mUpdateTime); out.writeLong(mUnpluggedTime); } @@ -346,19 +370,15 @@ public final class BatteryStatsImpl extends BatteryStats { } public void plug(long batteryUptime, long batteryRealtime) { - if (mNesting > 0) { - if (DEBUG && mType < 0) { - Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime - + " old mTotalTime=" + mTotalTime - + " old mUpdateTime=" + mUpdateTime); - } - mTotalTime = computeRunTimeLocked(batteryRealtime); - mUpdateTime = batteryRealtime; - if (DEBUG && mType < 0) { - Log.v(TAG, "plug #" + mType - + ": new mTotalTime=" + mTotalTime - + " old mUpdateTime=" + mUpdateTime); - } + if (DEBUG && mType < 0) { + Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime + + " old mTotalTime=" + mTotalTime); + } + mTotalTime = computeRunTimeLocked(batteryRealtime); + mCount = computeCurrentCountLocked(); + if (DEBUG && mType < 0) { + Log.v(TAG, "plug #" + mType + + ": new mTotalTime=" + mTotalTime); } } @@ -380,7 +400,7 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public long getTotalTime(long batteryRealtime, int which) { + public long getTotalTimeLocked(long batteryRealtime, int which) { long val; if (which == STATS_LAST) { val = mLastTime; @@ -397,12 +417,12 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public int getCount(int which) { + public int getCountLocked(int which) { int val; if (which == STATS_LAST) { val = mLastCount; } else { - val = mCount; + val = computeCurrentCountLocked(); if (which == STATS_UNPLUGGED) { val -= mUnpluggedCount; } else if (which != STATS_TOTAL) { @@ -414,14 +434,239 @@ public final class BatteryStatsImpl extends BatteryStats { } public void logState(Printer pw, String prefix) { - pw.println(prefix + "mNesting=" + mNesting + " mCount=" + mCount + pw.println(prefix + " mCount=" + mCount + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount + " mUnpluggedCount=" + mUnpluggedCount); pw.println(prefix + "mTotalTime=" + mTotalTime + " mLoadedTime=" + mLoadedTime); pw.println(prefix + "mLastTime=" + mLastTime + " mUnpluggedTime=" + mUnpluggedTime); - pw.println(prefix + "mUpdateTime=" + mUpdateTime + } + + + void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { + long runTime = computeRunTimeLocked(batteryRealtime); + // Divide by 1000 for backwards compatibility + out.writeLong((runTime + 500) / 1000); + out.writeLong(((runTime - mLoadedTime) + 500) / 1000); + out.writeInt(mCount); + out.writeInt(mCount - mLoadedCount); + } + + void readSummaryFromParcelLocked(Parcel in) { + // Multiply by 1000 for backwards compatibility + mTotalTime = mLoadedTime = in.readLong() * 1000; + mLastTime = in.readLong() * 1000; + mUnpluggedTime = mTotalTime; + mCount = mLoadedCount = in.readInt(); + mLastCount = in.readInt(); + mUnpluggedCount = mCount; + } + } + + public static final class SamplingTimer extends Timer { + + /** + * The most recent reported count from /proc/wakelocks. + */ + int mCurrentReportedCount; + + /** + * The reported count from /proc/wakelocks when unplug() was last + * called. + */ + int mUnpluggedReportedCount; + + /** + * The most recent reported total_time from /proc/wakelocks. + */ + long mCurrentReportedTotalTime; + + + /** + * The reported total_time from /proc/wakelocks when unplug() was last + * called. + */ + long mUnpluggedReportedTotalTime; + + /** + * Whether we are currently in a discharge cycle. + */ + boolean mInDischarge; + + /** + * Whether we are currently recording reported values. + */ + boolean mTrackingReportedValues; + + /* + * A sequnce counter, incremented once for each update of the stats. + */ + int mUpdateVersion; + + SamplingTimer(ArrayList unpluggables, boolean inDischarge, Parcel in) { + super(0, unpluggables, in); + mCurrentReportedCount = in.readInt(); + mUnpluggedReportedCount = in.readInt(); + mCurrentReportedTotalTime = in.readLong(); + mUnpluggedReportedTotalTime = in.readLong(); + mTrackingReportedValues = in.readInt() == 1; + mInDischarge = inDischarge; + } + + SamplingTimer(ArrayList unpluggables, boolean inDischarge, + boolean trackReportedValues) { + super(0, unpluggables); + mTrackingReportedValues = trackReportedValues; + mInDischarge = inDischarge; + } + + public void setStale() { + mTrackingReportedValues = false; + mUnpluggedReportedTotalTime = 0; + mUnpluggedReportedCount = 0; + } + + public void setUpdateVersion(int version) { + mUpdateVersion = version; + } + + public int getUpdateVersion() { + return mUpdateVersion; + } + + public void updateCurrentReportedCount(int count) { + if (mInDischarge && mUnpluggedReportedCount == 0) { + // Updating the reported value for the first time. + mUnpluggedReportedCount = count; + // If we are receiving an update update mTrackingReportedValues; + mTrackingReportedValues = true; + } + mCurrentReportedCount = count; + } + + public void updateCurrentReportedTotalTime(long totalTime) { + if (mInDischarge && mUnpluggedReportedTotalTime == 0) { + // Updating the reported value for the first time. + mUnpluggedReportedTotalTime = totalTime; + // If we are receiving an update update mTrackingReportedValues; + mTrackingReportedValues = true; + } + mCurrentReportedTotalTime = totalTime; + } + + public void unplug(long batteryUptime, long batteryRealtime) { + super.unplug(batteryUptime, batteryRealtime); + if (mTrackingReportedValues) { + mUnpluggedReportedTotalTime = mCurrentReportedTotalTime; + mUnpluggedReportedCount = mCurrentReportedCount; + } + mInDischarge = true; + } + + public void plug(long batteryUptime, long batteryRealtime) { + super.plug(batteryUptime, batteryRealtime); + mInDischarge = false; + } + + public void logState(Printer pw, String prefix) { + super.logState(pw, prefix); + pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount + + " mUnpluggedReportedCount=" + mUnpluggedReportedCount + + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime + + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime); + } + + protected long computeRunTimeLocked(long curBatteryRealtime) { + return mTotalTime + (mInDischarge && mTrackingReportedValues + ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0); + } + + protected int computeCurrentCountLocked() { + return mCount + (mInDischarge && mTrackingReportedValues + ? mCurrentReportedCount - mUnpluggedReportedCount : 0); + } + + public void writeToParcel(Parcel out, long batteryRealtime) { + super.writeToParcel(out, batteryRealtime); + out.writeInt(mCurrentReportedCount); + out.writeInt(mUnpluggedReportedCount); + out.writeLong(mCurrentReportedTotalTime); + out.writeLong(mUnpluggedReportedTotalTime); + out.writeInt(mTrackingReportedValues ? 1 : 0); + } + + void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { + super.writeSummaryFromParcelLocked(out, batteryRealtime); + out.writeLong(mCurrentReportedTotalTime); + out.writeInt(mCurrentReportedCount); + out.writeInt(mTrackingReportedValues ? 1 : 0); + } + + void readSummaryFromParcelLocked(Parcel in) { + super.readSummaryFromParcelLocked(in); + mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong(); + mUnpluggedReportedCount = mCurrentReportedCount = in.readInt(); + mTrackingReportedValues = in.readInt() == 1; + } + } + + /** + * State for keeping track of timing information. + */ + public static final class StopwatchTimer extends Timer { + final ArrayList mTimerPool; + int mNesting; + + + /** + * The last time at which we updated the timer. If mNesting is > 0, + * subtract this from the current battery time to find the amount of + * time we have been running since we last computed an update. + */ + long mUpdateTime; + + /** + * The total time at which the timer was acquired, to determine if + * was actually held for an interesting duration. + */ + long mAcquireTime; + + + StopwatchTimer(int type, ArrayList timerPool, + ArrayList unpluggables, Parcel in) { + super(type, unpluggables, in); + mTimerPool = timerPool; + mUpdateTime = in.readLong(); + } + + StopwatchTimer(int type, ArrayList timerPool, + ArrayList unpluggables) { + super(type, unpluggables); + mTimerPool = timerPool; + } + + public void writeToParcel(Parcel out, long batteryRealtime) { + super.writeToParcel(out, batteryRealtime); + out.writeLong(mUpdateTime); + } + + public void plug(long batteryUptime, long batteryRealtime) { + if (mNesting > 0) { + if (DEBUG && mType < 0) { + Log.v(TAG, "old mUpdateTime=" + mUpdateTime); + } + super.plug(batteryUptime, batteryRealtime); + mUpdateTime = batteryRealtime; + if (DEBUG && mType < 0) { + Log.v(TAG, "new mUpdateTime=" + mUpdateTime); + } + } + } + + public void logState(Printer pw, String prefix) { + super.logState(pw, prefix); + pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime + " mAcquireTime=" + mAcquireTime); } @@ -484,12 +729,12 @@ public final class BatteryStatsImpl extends BatteryStats { // Update the total time for all other running Timers with the same type as this Timer // due to a change in timer count private static void refreshTimersLocked(final BatteryStatsImpl stats, - final ArrayList pool) { + final ArrayList pool) { final long realtime = SystemClock.elapsedRealtime() * 1000; final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime); final int N = pool.size(); for (int i=N-1; i>= 0; i--) { - final Timer t = pool.get(i); + final StopwatchTimer t = pool.get(i); long heldTime = batteryRealtime - t.mUpdateTime; if (heldTime > 0) { t.mTotalTime += heldTime / N; @@ -498,34 +743,146 @@ public final class BatteryStatsImpl extends BatteryStats { } } - private long computeRunTimeLocked(long curBatteryRealtime) { + @Override + protected long computeRunTimeLocked(long curBatteryRealtime) { return mTotalTime + (mNesting > 0 ? (curBatteryRealtime - mUpdateTime) / (mTimerPool != null ? mTimerPool.size() : 1) : 0); } - void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { - long runTime = computeRunTimeLocked(batteryRealtime); - // Divide by 1000 for backwards compatibility - out.writeLong((runTime + 500) / 1000); - out.writeLong(((runTime - mLoadedTime) + 500) / 1000); - out.writeInt(mCount); - out.writeInt(mCount - mLoadedCount); + @Override + protected int computeCurrentCountLocked() { + return mCount; } void readSummaryFromParcelLocked(Parcel in) { - // Multiply by 1000 for backwards compatibility - mTotalTime = mLoadedTime = in.readLong() * 1000; - mLastTime = in.readLong() * 1000; - mUnpluggedTime = mTotalTime; - mCount = mLoadedCount = in.readInt(); - mLastCount = in.readInt(); - mUnpluggedCount = mCount; + super.readSummaryFromParcelLocked(in); mNesting = 0; } } + private final Map readKernelWakelockStats() { + + byte[] buffer = new byte[4096]; + int len; + + try { + FileInputStream is = new FileInputStream("/proc/wakelocks"); + len = is.read(buffer); + is.close(); + + if (len > 0) { + int i; + for (i=0; i parseProcWakelocks( + byte[] wlBuffer, int len) { + String name; + int count; + long totalTime; + int startIndex, endIndex; + int numUpdatedWlNames = 0; + + // Advance past the first line. + int i; + for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++); + startIndex = endIndex = i + 1; + + synchronized(this) { + Map m = mProcWakelockFileStats; + + sKernelWakelockUpdateVersion++; + while (endIndex < len) { + for (endIndex=startIndex; + endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; + endIndex++); + endIndex++; // endIndex is an exclusive upper bound. + + String[] nameStringArray = mProcWakelocksName; + long[] wlData = mProcWakelocksData; + Process.parseProcLine(wlBuffer, startIndex, endIndex, PROC_WAKELOCKS_FORMAT, + nameStringArray, wlData, null); + + name = nameStringArray[0]; + count = (int) wlData[1]; + // convert nanoseconds to microseconds with rounding. + totalTime = (wlData[2] + 500) / 1000; + + if (name.length() > 0) { + if (!m.containsKey(name)) { + m.put(name, new KernelWakelockStats(count, totalTime, + sKernelWakelockUpdateVersion)); + numUpdatedWlNames++; + } else { + KernelWakelockStats kwlStats = m.get(name); + if (kwlStats.mVersion == sKernelWakelockUpdateVersion) { + kwlStats.mCount += count; + kwlStats.mTotalTime += totalTime; + } else { + kwlStats.mCount = count; + kwlStats.mTotalTime = totalTime; + kwlStats.mVersion = sKernelWakelockUpdateVersion; + numUpdatedWlNames++; + } + } + } + startIndex = endIndex; + } + + if (m.size() != numUpdatedWlNames) { + // Don't report old data. + Iterator itr = m.values().iterator(); + while (itr.hasNext()) { + if (itr.next().mVersion != sKernelWakelockUpdateVersion) { + itr.remove(); + } + } + } + return m; + } + } + + private class KernelWakelockStats { + public int mCount; + public long mTotalTime; + public int mVersion; + + KernelWakelockStats(int count, long totalTime, int version) { + mCount = count; + mTotalTime = totalTime; + mVersion = version; + } + } + + /* + * Get the KernelWakelockTimer associated with name, and create a new one if one + * doesn't already exist. + */ + public SamplingTimer getKernelWakelockTimerLocked(String name) { + SamplingTimer kwlt = mKernelWakelockStats.get(name); + if (kwlt == null) { + kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, + true /* track reported values */); + mKernelWakelockStats.put(name, kwlt); + } + return kwlt; + } + public void doUnplug(long batteryUptime, long batteryRealtime) { for (int iu = mUidStats.size() - 1; iu >= 0; iu--) { Uid u = mUidStats.valueAt(iu); @@ -758,55 +1115,69 @@ public final class BatteryStatsImpl extends BatteryStats { u.noteScanWifiLockReleasedLocked(); } } - + + public void noteWifiMulticastEnabledLocked(int uid) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.noteWifiMulticastEnabledLocked(); + } + } + + public void noteWifiMulticastDisabledLocked(int uid) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.noteWifiMulticastDisabledLocked(); + } + } + @Override public long getScreenOnTime(long batteryRealtime, int which) { - return mScreenOnTimer.getTotalTime(batteryRealtime, which); + return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getScreenBrightnessTime(int brightnessBin, long batteryRealtime, int which) { - return mScreenBrightnessTimer[brightnessBin].getTotalTime( + return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked( batteryRealtime, which); } @Override public int getInputEventCount(int which) { - return mInputEventCounter.getCount(which); + return mInputEventCounter.getCountLocked(which); } @Override public long getPhoneOnTime(long batteryRealtime, int which) { - return mPhoneOnTimer.getTotalTime(batteryRealtime, which); + return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getPhoneSignalStrengthTime(int strengthBin, long batteryRealtime, int which) { - return mPhoneSignalStrengthsTimer[strengthBin].getTotalTime( + return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked( batteryRealtime, which); } @Override public int getPhoneSignalStrengthCount(int dataType, int which) { - return mPhoneDataConnectionsTimer[dataType].getCount(which); + return mPhoneDataConnectionsTimer[dataType].getCountLocked(which); } @Override public long getPhoneDataConnectionTime(int dataType, long batteryRealtime, int which) { - return mPhoneDataConnectionsTimer[dataType].getTotalTime( + return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked( batteryRealtime, which); } @Override public int getPhoneDataConnectionCount(int dataType, int which) { - return mPhoneDataConnectionsTimer[dataType].getCount(which); + return mPhoneDataConnectionsTimer[dataType].getCountLocked(which); } @Override public long getWifiOnTime(long batteryRealtime, int which) { - return mWifiOnTimer.getTotalTime(batteryRealtime, which); + return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getWifiRunningTime(long batteryRealtime, int which) { - return mWifiRunningTimer.getTotalTime(batteryRealtime, which); + return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getBluetoothOnTime(long batteryRealtime, int which) { - return mBluetoothOnTimer.getTotalTime(batteryRealtime, which); + return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public boolean getIsOnBattery() { @@ -836,14 +1207,17 @@ public final class BatteryStatsImpl extends BatteryStats { long mStartedTcpBytesSent = -1; boolean mWifiTurnedOn; - Timer mWifiTurnedOnTimer; + StopwatchTimer mWifiTurnedOnTimer; boolean mFullWifiLockOut; - Timer mFullWifiLockTimer; + StopwatchTimer mFullWifiLockTimer; boolean mScanWifiLockOut; - Timer mScanWifiLockTimer; - + StopwatchTimer mScanWifiLockTimer; + + boolean mWifiMulticastEnabled; + StopwatchTimer mWifiMulticastTimer; + Counter[] mUserActivityCounters; /** @@ -868,9 +1242,11 @@ public final class BatteryStatsImpl extends BatteryStats { public Uid(int uid) { mUid = uid; - mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables); - mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables); - mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables); + mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables); + mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables); + mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables); + mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED, + null, mUnpluggables); } @Override @@ -977,22 +1353,44 @@ public final class BatteryStatsImpl extends BatteryStats { mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this); } } - + + @Override + public void noteWifiMulticastEnabledLocked() { + if (!mWifiMulticastEnabled) { + mWifiMulticastEnabled = true; + mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this); + } + } + + @Override + public void noteWifiMulticastDisabledLocked() { + if (mWifiMulticastEnabled) { + mWifiMulticastEnabled = false; + mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this); + } + } + @Override public long getWifiTurnedOnTime(long batteryRealtime, int which) { - return mWifiTurnedOnTimer.getTotalTime(batteryRealtime, which); + return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getFullWifiLockTime(long batteryRealtime, int which) { - return mFullWifiLockTimer.getTotalTime(batteryRealtime, which); + return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which); } @Override public long getScanWifiLockTime(long batteryRealtime, int which) { - return mScanWifiLockTimer.getTotalTime(batteryRealtime, which); + return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which); } - + + @Override + public long getWifiMulticastTime(long batteryRealtime, int which) { + return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime, + which); + } + @Override public void noteUserActivityLocked(int type) { if (mUserActivityCounters == null) { @@ -1013,7 +1411,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (mUserActivityCounters == null) { return 0; } - return mUserActivityCounters[type].getCount(which); + return mUserActivityCounters[type].getCountLocked(which); } void initUserActivityLocked() { @@ -1066,6 +1464,7 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime); mFullWifiLockTimer.writeToParcel(out, batteryRealtime); mScanWifiLockTimer.writeToParcel(out, batteryRealtime); + mWifiMulticastTimer.writeToParcel(out, batteryRealtime); if (mUserActivityCounters == null) { out.writeInt(0); } else { @@ -1120,11 +1519,14 @@ public final class BatteryStatsImpl extends BatteryStats { mTcpBytesReceivedAtLastUnplug = in.readLong(); mTcpBytesSentAtLastUnplug = in.readLong(); mWifiTurnedOn = false; - mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables, in); + mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in); mFullWifiLockOut = false; - mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables, in); + mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in); mScanWifiLockOut = false; - mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables, in); + mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in); + mWifiMulticastEnabled = false; + mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED, + null, mUnpluggables, in); if (in.readInt() == 0) { mUserActivityCounters = null; } else { @@ -1142,17 +1544,17 @@ public final class BatteryStatsImpl extends BatteryStats { /** * How long (in ms) this uid has been keeping the device partially awake. */ - Timer mTimerPartial; + StopwatchTimer mTimerPartial; /** * How long (in ms) this uid has been keeping the device fully awake. */ - Timer mTimerFull; + StopwatchTimer mTimerFull; /** * How long (in ms) this uid has had a window keeping the device awake. */ - Timer mTimerWindow; + StopwatchTimer mTimerWindow; /** * Reads a possibly null Timer from a Parcel. The timer is associated with the @@ -1161,13 +1563,13 @@ public final class BatteryStatsImpl extends BatteryStats { * @param in the Parcel to be read from. * return a new Timer, or null. */ - private Timer readTimerFromParcel(int type, ArrayList pool, + private StopwatchTimer readTimerFromParcel(int type, ArrayList pool, ArrayList unpluggables, Parcel in) { if (in.readInt() == 0) { return null; } - return new Timer(type, pool, unpluggables, in); + return new StopwatchTimer(type, pool, unpluggables, in); } void readFromParcelLocked(ArrayList unpluggables, Parcel in) { @@ -1198,24 +1600,24 @@ public final class BatteryStatsImpl extends BatteryStats { public final class Sensor extends BatteryStats.Uid.Sensor { final int mHandle; - Timer mTimer; + StopwatchTimer mTimer; public Sensor(int handle) { mHandle = handle; } - private Timer readTimerFromParcel(ArrayList unpluggables, + private StopwatchTimer readTimerFromParcel(ArrayList unpluggables, Parcel in) { if (in.readInt() == 0) { return null; } - ArrayList pool = mSensorTimers.get(mHandle); + ArrayList pool = mSensorTimers.get(mHandle); if (pool == null) { - pool = new ArrayList(); + pool = new ArrayList(); mSensorTimers.put(mHandle, pool); } - return new Timer(0, pool, unpluggables, in); + return new StopwatchTimer(0, pool, unpluggables, in); } void readFromParcelLocked(ArrayList unpluggables, Parcel in) { @@ -1816,32 +2218,32 @@ public final class BatteryStatsImpl extends BatteryStats { return ss; } - public Timer getWakeTimerLocked(String name, int type) { + public StopwatchTimer getWakeTimerLocked(String name, int type) { Wakelock wl = mWakelockStats.get(name); if (wl == null) { wl = new Wakelock(); mWakelockStats.put(name, wl); } - Timer t = null; + StopwatchTimer t = null; switch (type) { case WAKE_TYPE_PARTIAL: t = wl.mTimerPartial; if (t == null) { - t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables); + t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables); wl.mTimerPartial = t; } return t; case WAKE_TYPE_FULL: t = wl.mTimerFull; if (t == null) { - t = new Timer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables); + t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables); wl.mTimerFull = t; } return t; case WAKE_TYPE_WINDOW: t = wl.mTimerWindow; if (t == null) { - t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables); + t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables); wl.mTimerWindow = t; } return t; @@ -1850,7 +2252,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public Timer getSensorTimerLocked(int sensor, boolean create) { + public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) { Sensor se = mSensorStats.get(sensor); if (se == null) { if (!create) { @@ -1859,36 +2261,36 @@ public final class BatteryStatsImpl extends BatteryStats { se = new Sensor(sensor); mSensorStats.put(sensor, se); } - Timer t = se.mTimer; + StopwatchTimer t = se.mTimer; if (t != null) { return t; } - ArrayList timers = mSensorTimers.get(sensor); + ArrayList timers = mSensorTimers.get(sensor); if (timers == null) { - timers = new ArrayList(); + timers = new ArrayList(); mSensorTimers.put(sensor, timers); } - t = new Timer(BatteryStats.SENSOR, timers, mUnpluggables); + t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables); se.mTimer = t; return t; } public void noteStartWakeLocked(String name, int type) { - Timer t = getWakeTimerLocked(name, type); + StopwatchTimer t = getWakeTimerLocked(name, type); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); } } public void noteStopWakeLocked(String name, int type) { - Timer t = getWakeTimerLocked(name, type); + StopwatchTimer t = getWakeTimerLocked(name, type); if (t != null) { t.stopRunningLocked(BatteryStatsImpl.this); } } public void noteStartSensor(int sensor) { - Timer t = getSensorTimerLocked(sensor, true); + StopwatchTimer t = getSensorTimerLocked(sensor, true); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); } @@ -1896,21 +2298,21 @@ public final class BatteryStatsImpl extends BatteryStats { public void noteStopSensor(int sensor) { // Don't create a timer if one doesn't already exist - Timer t = getSensorTimerLocked(sensor, false); + StopwatchTimer t = getSensorTimerLocked(sensor, false); if (t != null) { t.stopRunningLocked(BatteryStatsImpl.this); } } public void noteStartGps() { - Timer t = getSensorTimerLocked(Sensor.GPS, true); + StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true); if (t != null) { t.startRunningLocked(BatteryStatsImpl.this); } } public void noteStopGps() { - Timer t = getSensorTimerLocked(Sensor.GPS, false); + StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false); if (t != null) { t.stopRunningLocked(BatteryStatsImpl.this); } @@ -1925,21 +2327,21 @@ public final class BatteryStatsImpl extends BatteryStats { mFile = new File(filename); mBackupFile = new File(filename + ".bak"); mStartCount++; - mScreenOnTimer = new Timer(-1, null, mUnpluggables); + mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables); for (int i=0; i m = readKernelWakelockStats(); + + if (m == null) { + // Not crashing might make board bringup easier. + Log.w(TAG, "Couldn't get kernel wake lock stats"); + return; + } + + for (Map.Entry ent : m.entrySet()) { + String name = ent.getKey(); + KernelWakelockStats kws = ent.getValue(); + + SamplingTimer kwlt = mKernelWakelockStats.get(name); + if (kwlt == null) { + kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, + true /* track reported values */); + mKernelWakelockStats.put(name, kwlt); + } + kwlt.updateCurrentReportedCount(kws.mCount); + kwlt.updateCurrentReportedTotalTime(kws.mTotalTime); + kwlt.setUpdateVersion(sKernelWakelockUpdateVersion); + } + + if (m.size() != mKernelWakelockStats.size()) { + // Set timers to stale if they didn't appear in /proc/wakelocks this time. + for (Map.Entry ent : mKernelWakelockStats.entrySet()) { + SamplingTimer st = ent.getValue(); + if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) { + st.setStale(); + } + } + } + } public long getAwakeTimeBattery() { return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT); @@ -2086,25 +2528,25 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public int getUnpluggedStartLevel() { + public int getDischargeStartLevel() { synchronized(this) { - return getUnluggedStartLevelLocked(); + return getDischargeStartLevelLocked(); } } - public int getUnluggedStartLevelLocked() { - return mUnpluggedStartLevel; + public int getDischargeStartLevelLocked() { + return mDischargeStartLevel; } @Override - public int getPluggedStartLevel() { + public int getDischargeCurrentLevel() { synchronized(this) { - return getPluggedStartLevelLocked(); + return getDischargeCurrentLevelLocked(); } } - public int getPluggedStartLevelLocked() { - return mPluggedStartLevel; + public int getDischargeCurrentLevelLocked() { + return mDischargeCurrentLevel; } /** @@ -2266,8 +2708,8 @@ public final class BatteryStatsImpl extends BatteryStats { mLastUptime = in.readLong(); mRealtime = in.readLong(); mLastRealtime = in.readLong(); - mUnpluggedStartLevel = in.readInt(); - mPluggedStartLevel = in.readInt(); + mDischargeStartLevel = in.readInt(); + mDischargeCurrentLevel = in.readInt(); mStartCount++; @@ -2292,6 +2734,14 @@ public final class BatteryStatsImpl extends BatteryStats { mBluetoothOn = false; mBluetoothOnTimer.readSummaryFromParcelLocked(in); + int NKW = in.readInt(); + for (int ikw = 0; ikw < NKW; ikw++) { + if (in.readInt() != 0) { + String kwltName = in.readString(); + getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in); + } + } + final int NU = in.readInt(); for (int iu = 0; iu < NU; iu++) { int uid = in.readInt(); @@ -2304,7 +2754,9 @@ public final class BatteryStatsImpl extends BatteryStats { u.mFullWifiLockTimer.readSummaryFromParcelLocked(in); u.mScanWifiLockOut = false; u.mScanWifiLockTimer.readSummaryFromParcelLocked(in); - + u.mWifiMulticastEnabled = false; + u.mWifiMulticastTimer.readSummaryFromParcelLocked(in); + if (in.readInt() != 0) { if (u.mUserActivityCounters == null) { u.initUserActivityLocked(); @@ -2396,8 +2848,8 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT)); out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL)); out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT)); - out.writeInt(mUnpluggedStartLevel); - out.writeInt(mPluggedStartLevel); + out.writeInt(mDischargeStartLevel); + out.writeInt(mDischargeCurrentLevel); mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); @@ -2416,6 +2868,18 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL); mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); + out.writeInt(mKernelWakelockStats.size()); + for (Map.Entry ent : mKernelWakelockStats.entrySet()) { + Timer kwlt = ent.getValue(); + if (kwlt != null) { + out.writeInt(1); + out.writeString(ent.getKey()); + ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL); + } else { + out.writeInt(0); + } + } + final int NU = mUidStats.size(); out.writeInt(NU); for (int iu = 0; iu < NU; iu++) { @@ -2425,6 +2889,7 @@ public final class BatteryStatsImpl extends BatteryStats { u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL); u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL); + u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL); if (u.mUserActivityCounters == null) { out.writeInt(0); @@ -2544,25 +3009,25 @@ public final class BatteryStatsImpl extends BatteryStats { mBatteryRealtime = in.readLong(); mBatteryLastRealtime = in.readLong(); mScreenOn = false; - mScreenOnTimer = new Timer(-1, null, mUnpluggables, in); + mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in); for (int i=0; i ent : mKernelWakelockStats.entrySet()) { + SamplingTimer kwlt = ent.getValue(); + if (kwlt != null) { + out.writeInt(1); + out.writeString(ent.getKey()); + Timer.writeTimerToParcel(out, kwlt, batteryRealtime); + } else { + out.writeInt(0); + } + } + int size = mUidStats.size(); out.writeInt(size); for (int i = 0; i < size; i++) { @@ -2665,32 +3152,33 @@ public final class BatteryStatsImpl extends BatteryStats { } }; - public void dumpLocked(Printer pw) { + public void dumpLocked(PrintWriter pw) { if (DEBUG) { - pw.println("*** Screen timer:"); - mScreenOnTimer.logState(pw, " "); + Printer pr = new PrintWriterPrinter(pw); + pr.println("*** Screen timer:"); + mScreenOnTimer.logState(pr, " "); for (int i=0; i>> 3; + int offset = 16 - (mPos & 0x07) - bits; // &7==%8 + if ((bits < 0) || (bits > 8) || ((mPos + bits) > mEnd)) { + throw new AccessException("illegal read " + + "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); + } + int data = (mBuf[index] & 0x00FF) << 8; + if (offset < 8) data |= (mBuf[index + 1] & 0xFF); + data >>>= offset; + data &= (-1 >>> (32 - bits)); + mPos += bits; + return (byte)data; + } + + /** + * Read data in bulk into a byte array and increment the current position. + * + * @param bits the amount of data to read + * + * @return newly allocated byte array of read data + */ + public byte[] readByteArray(int bits) throws AccessException { + int bytes = (bits >>> 3) + ((bits & 0x07) > 0 ? 1 : 0); // &7==%8 + byte[] arr = new byte[bytes]; + for (int i = 0; i < bytes; i++) { + int increment = Math.min(8, bits - (i << 3)); + arr[i] = (byte)(read(increment) << (8 - increment)); + } + return arr; + } + + /** + * Increment the current position and ignore contained data. + * + * @param bits the amount by which to increment the position + */ + public void skip(int bits) throws AccessException { + if ((mPos + bits) > mEnd) { + throw new AccessException("illegal skip " + + "(pos " + mPos + ", end " + mEnd + ", bits " + bits + ")"); + } + mPos += bits; + } +} diff --git a/core/java/com/android/internal/util/BitwiseOutputStream.java b/core/java/com/android/internal/util/BitwiseOutputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..1b974ce4c9ee6f798272435d4dc6538cf2d95259 --- /dev/null +++ b/core/java/com/android/internal/util/BitwiseOutputStream.java @@ -0,0 +1,126 @@ +/* + * 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; + +/** + * An object that provides bitwise incremental write access to a byte array. + * + * This is useful, for example, when writing a series of fields that + * may not be aligned on byte boundaries. + * + * NOTE -- This class is not threadsafe. + */ +public class BitwiseOutputStream { + + // The byte array being written to, which will be grown as needed. + private byte[] mBuf; + + // The current position offset, in bits, from the msb in byte 0. + private int mPos; + + // The last bit offset, given the current buf length. + private int mEnd; + + /** + * An exception to report access problems. + */ + public static class AccessException extends Exception { + public AccessException(String s) { + super("BitwiseOutputStream access failed: " + s); + } + } + + /** + * Create object from hint at desired size. + * + * @param startingLength initial internal byte array length in bytes + */ + public BitwiseOutputStream(int startingLength) { + mBuf = new byte[startingLength]; + mEnd = startingLength << 3; + mPos = 0; + } + + /** + * Return byte array containing accumulated data, sized to just fit. + * + * @return newly allocated byte array + */ + public byte[] toByteArray() { + int len = (mPos >>> 3) + ((mPos & 0x07) > 0 ? 1 : 0); // &7==%8 + byte[] newBuf = new byte[len]; + System.arraycopy(mBuf, 0, newBuf, 0, len); + return newBuf; + } + + /** + * Allocate a new internal buffer, if needed. + * + * @param bits additional bits to be accommodated + */ + private void possExpand(int bits) { + if ((mPos + bits) < mEnd) return; + byte[] newBuf = new byte[(mPos + bits) >>> 2]; + System.arraycopy(mBuf, 0, newBuf, 0, mEnd >>> 3); + mBuf = newBuf; + } + + /** + * Write some data and increment the current position. + * + * @param bits the amount of data to write (gte 0, lte 8) + * @param data to write, will be masked to expose only bits param from lsb + */ + public void write(int bits, int data) throws AccessException { + if ((bits < 0) || (bits > 8)) { + throw new AccessException("illegal write (" + bits + " bits)"); + } + possExpand(bits); + data &= (-1 >>> (32 - bits)); + int index = mPos >>> 3; + int offset = 16 - (mPos & 0x07) - bits; // &7==%8 + data <<= offset; + mPos += bits; + mBuf[index] |= (data >>> 8); + if (offset < 8) mBuf[index + 1] |= (data & 0x00FF); + } + + /** + * Write data in bulk from a byte array and increment the current position. + * + * @param bits the amount of data to write + * @param arr the byte array containing data to be written + */ + public void writeByteArray(int bits, byte[] arr) throws AccessException { + for (int i = 0; i < arr.length; i++) { + int increment = Math.min(8, bits - (i << 3)); + if (increment > 0) { + write(increment, (byte)(arr[i] >>> (8 - increment))); + } + } + } + + /** + * Increment the current position, implicitly writing zeros. + * + * @param bits the amount by which to increment the position + */ + public void skip(int bits) { + possExpand(bits); + mPos += bits; + } +} diff --git a/core/java/com/android/internal/util/TypedProperties.java b/core/java/com/android/internal/util/TypedProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..c2ce21026831e929da638917d62a0b7c5b8393e2 --- /dev/null +++ b/core/java/com/android/internal/util/TypedProperties.java @@ -0,0 +1,714 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import java.io.IOException; +import java.io.Reader; +import java.io.StreamTokenizer; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * A {@code Map} that publishes a set of typed properties, defined by + * zero or more {@code Reader}s containing textual definitions and assignments. + */ +public class TypedProperties extends HashMap { + /** + * Instantiates a {@link java.io.StreamTokenizer} and sets its syntax tables + * appropriately for the {@code TypedProperties} file format. + * + * @param r The {@code Reader} that the {@code StreamTokenizer} will read from + * @return a newly-created and initialized {@code StreamTokenizer} + */ + static StreamTokenizer initTokenizer(Reader r) { + StreamTokenizer st = new StreamTokenizer(r); + + // Treat everything we don't specify as "ordinary". + st.resetSyntax(); + + /* The only non-quoted-string words we'll be reading are: + * - property names: [._$a-zA-Z0-9] + * - type names: [a-zS] + * - number literals: [-0-9.eExXA-Za-z] ('x' for 0xNNN hex literals. "NaN", "Infinity") + * - "true" or "false" (case insensitive): [a-zA-Z] + */ + st.wordChars('0', '9'); + st.wordChars('A', 'Z'); + st.wordChars('a', 'z'); + st.wordChars('_', '_'); + st.wordChars('$', '$'); + st.wordChars('.', '.'); + st.wordChars('-', '-'); + st.wordChars('+', '+'); + + // Single-character tokens + st.ordinaryChar('='); + + // Other special characters + st.whitespaceChars(' ', ' '); + st.whitespaceChars('\t', '\t'); + st.whitespaceChars('\n', '\n'); + st.whitespaceChars('\r', '\r'); + st.quoteChar('"'); + + // Java-style comments + st.slashStarComments(true); + st.slashSlashComments(true); + + return st; + } + + + /** + * An unchecked exception that is thrown when encountering a syntax + * or semantic error in the input. + */ + public static class ParseException extends IllegalArgumentException { + ParseException(StreamTokenizer state, String expected) { + super("expected " + expected + ", saw " + state.toString()); + } + } + + // A sentinel instance used to indicate a null string. + static final String NULL_STRING = new String(""); + + // Constants used to represent the supported types. + static final int TYPE_UNSET = 'x'; + static final int TYPE_BOOLEAN = 'Z'; + static final int TYPE_BYTE = 'I' | 1 << 8; + // TYPE_CHAR: character literal syntax not supported; use short. + static final int TYPE_SHORT = 'I' | 2 << 8; + static final int TYPE_INT = 'I' | 4 << 8; + static final int TYPE_LONG = 'I' | 8 << 8; + static final int TYPE_FLOAT = 'F' | 4 << 8; + static final int TYPE_DOUBLE = 'F' | 8 << 8; + static final int TYPE_STRING = 'L' | 's' << 8; + static final int TYPE_ERROR = -1; + + /** + * Converts a string to an internal type constant. + * + * @param typeName the type name to convert + * @return the type constant that corresponds to {@code typeName}, + * or {@code TYPE_ERROR} if the type is unknown + */ + static int interpretType(String typeName) { + if ("unset".equals(typeName)) { + return TYPE_UNSET; + } else if ("boolean".equals(typeName)) { + return TYPE_BOOLEAN; + } else if ("byte".equals(typeName)) { + return TYPE_BYTE; + } else if ("short".equals(typeName)) { + return TYPE_SHORT; + } else if ("int".equals(typeName)) { + return TYPE_INT; + } else if ("long".equals(typeName)) { + return TYPE_LONG; + } else if ("float".equals(typeName)) { + return TYPE_FLOAT; + } else if ("double".equals(typeName)) { + return TYPE_DOUBLE; + } else if ("String".equals(typeName)) { + return TYPE_STRING; + } + return TYPE_ERROR; + } + + /** + * Parses the data in the reader. + * + * @param r The {@code Reader} containing input data to parse + * @param map The {@code Map} to insert parameter values into + * @throws ParseException if the input data is malformed + * @throws IOException if there is a problem reading from the {@code Reader} + */ + static void parse(Reader r, Map map) throws ParseException, IOException { + final StreamTokenizer st = initTokenizer(r); + + /* A property name must be a valid fully-qualified class + package name. + * We don't support Unicode, though. + */ + final String identifierPattern = "[a-zA-Z_$][0-9a-zA-Z_$]*"; + final Pattern propertyNamePattern = + Pattern.compile("(" + identifierPattern + "\\.)*" + identifierPattern); + + + while (true) { + int token; + + // Read the next token, which is either the type or EOF. + token = st.nextToken(); + if (token == StreamTokenizer.TT_EOF) { + break; + } + if (token != StreamTokenizer.TT_WORD) { + throw new ParseException(st, "type name"); + } + final int type = interpretType(st.sval); + if (type == TYPE_ERROR) { + throw new ParseException(st, "valid type name"); + } + st.sval = null; + + if (type == TYPE_UNSET) { + // Expect '('. + token = st.nextToken(); + if (token != '(') { + throw new ParseException(st, "'('"); + } + } + + // Read the property name. + token = st.nextToken(); + if (token != StreamTokenizer.TT_WORD) { + throw new ParseException(st, "property name"); + } + final String propertyName = st.sval; + if (!propertyNamePattern.matcher(propertyName).matches()) { + throw new ParseException(st, "valid property name"); + } + st.sval = null; + + if (type == TYPE_UNSET) { + // Expect ')'. + token = st.nextToken(); + if (token != ')') { + throw new ParseException(st, "')'"); + } + map.remove(propertyName); + } else { + // Expect '='. + token = st.nextToken(); + if (token != '=') { + throw new ParseException(st, "'='"); + } + + // Read a value of the appropriate type, and insert into the map. + final Object value = parseValue(st, type); + final Object oldValue = map.remove(propertyName); + if (oldValue != null) { + // TODO: catch the case where a string is set to null and then + // the same property is defined with a different type. + if (value.getClass() != oldValue.getClass()) { + throw new ParseException(st, + "(property previously declared as a different type)"); + } + } + map.put(propertyName, value); + } + + // Expect ';'. + token = st.nextToken(); + if (token != ';') { + throw new ParseException(st, "';'"); + } + } + } + + /** + * Parses the next token in the StreamTokenizer as the specified type. + * + * @param st The token source + * @param type The type to interpret next token as + * @return a Boolean, Number subclass, or String representing the value. + * Null strings are represented by the String instance NULL_STRING + * @throws IOException if there is a problem reading from the {@code StreamTokenizer} + */ + static Object parseValue(StreamTokenizer st, final int type) throws IOException { + final int token = st.nextToken(); + + if (type == TYPE_BOOLEAN) { + if (token != StreamTokenizer.TT_WORD) { + throw new ParseException(st, "boolean constant"); + } + + if ("true".equals(st.sval)) { + return Boolean.TRUE; + } else if ("false".equals(st.sval)) { + return Boolean.FALSE; + } + + throw new ParseException(st, "boolean constant"); + } else if ((type & 0xff) == 'I') { + if (token != StreamTokenizer.TT_WORD) { + throw new ParseException(st, "integer constant"); + } + + /* Parse the string. Long.decode() handles C-style integer constants + * ("0x" -> hex, "0" -> octal). It also treats numbers with a prefix of "#" as + * hex, but our syntax intentionally does not list '#' as a word character. + */ + long value; + try { + value = Long.decode(st.sval); + } catch (NumberFormatException ex) { + throw new ParseException(st, "integer constant"); + } + + // Ensure that the type can hold this value, and return. + int width = (type >> 8) & 0xff; + switch (width) { + case 1: + if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { + throw new ParseException(st, "8-bit integer constant"); + } + return new Byte((byte)value); + case 2: + if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { + throw new ParseException(st, "16-bit integer constant"); + } + return new Short((short)value); + case 4: + if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) { + throw new ParseException(st, "32-bit integer constant"); + } + return new Integer((int)value); + case 8: + if (value < Long.MIN_VALUE || value > Long.MAX_VALUE) { + throw new ParseException(st, "64-bit integer constant"); + } + return new Long(value); + default: + throw new IllegalStateException( + "Internal error; unexpected integer type width " + width); + } + } else if ((type & 0xff) == 'F') { + if (token != StreamTokenizer.TT_WORD) { + throw new ParseException(st, "float constant"); + } + + // Parse the string. + /* TODO: Maybe just parse as float or double, losing precision if necessary. + * Parsing as double and converting to float can change the value + * compared to just parsing as float. + */ + double value; + try { + /* TODO: detect if the string representation loses precision + * when being converted to a double. + */ + value = Double.parseDouble(st.sval); + } catch (NumberFormatException ex) { + throw new ParseException(st, "float constant"); + } + + // Ensure that the type can hold this value, and return. + if (((type >> 8) & 0xff) == 4) { + // This property is a float; make sure the value fits. + double absValue = Math.abs(value); + if (absValue != 0.0 && !Double.isInfinite(value) && !Double.isNaN(value)) { + if (absValue < Float.MIN_VALUE || absValue > Float.MAX_VALUE) { + throw new ParseException(st, "32-bit float constant"); + } + } + return new Float((float)value); + } else { + // This property is a double; no need to truncate. + return new Double(value); + } + } else if (type == TYPE_STRING) { + // Expect a quoted string or the word "null". + if (token == '"') { + return st.sval; + } else if (token == StreamTokenizer.TT_WORD && "null".equals(st.sval)) { + return NULL_STRING; + } + throw new ParseException(st, "double-quoted string or 'null'"); + } + + throw new IllegalStateException("Internal error; unknown type " + type); + } + + + /** + * Creates an empty TypedProperties instance. + */ + public TypedProperties() { + super(); + } + + /** + * Loads zero or more properties from the specified Reader. + * Properties that have already been loaded are preserved unless + * the new Reader overrides or unsets earlier values for the + * same properties. + *

        + * File syntax: + *

        + * + * <type> <property-name> = <value> ; + *
        + * unset ( <property-name> ) ; + *
        + *

        + * "//" comments everything until the end of the line. + * "/a;" comments everything until the next appearance of "a;/". + *

        + * Blank lines are ignored. + *

        + * The only required whitespace is between the type and + * the property name. + *

        + * <type> is one of {boolean, byte, short, int, long, + * float, double, String}, and is case-sensitive. + *

        + * <property-name> is a valid fully-qualified class name + * (one or more valid identifiers separated by dot characters). + *

        + * <value> depends on the type: + *

          + *
        • boolean: one of {true, false} (case-sensitive) + *
        • byte, short, int, long: a valid Java integer constant + * (including non-base-10 constants like 0xabc and 074) + * whose value does not overflow the type. NOTE: these are + * interpreted as Java integer values, so they are all signed. + *
        • float, double: a valid Java floating-point constant. + * If the type is float, the value must fit in 32 bits. + *
        • String: a double-quoted string value, or the word {@code null}. + * NOTE: the contents of the string must be 7-bit clean ASCII; + * C-style octal escapes are recognized, but Unicode escapes are not. + *
        + *

        + * Passing a property-name to {@code unset()} will unset the property, + * removing its value and type information, as if it had never been + * defined. + *

        + * + * @param r The Reader to load properties from + * @throws IOException if an error occurs when reading the data + * @throws IllegalArgumentException if the data is malformed + */ + public void load(Reader r) throws IOException { + parse(r, this); + } + + @Override + public Object get(Object key) { + Object value = super.get(key); + if (value == NULL_STRING) { + return null; + } + return value; + } + + /* + * Getters with explicit defaults + */ + + /** + * An unchecked exception that is thrown if a {@code get<TYPE>()} method + * is used to retrieve a parameter whose type does not match the method name. + */ + public static class TypeException extends IllegalArgumentException { + TypeException(String property, Object value, String requestedType) { + super(property + " has type " + value.getClass().getName() + + ", not " + requestedType); + } + } + + /** + * Returns the value of a boolean property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not a boolean + */ + public boolean getBoolean(String property, boolean def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value instanceof Boolean) { + return ((Boolean)value).booleanValue(); + } + throw new TypeException(property, value, "boolean"); + } + + /** + * Returns the value of a byte property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not a byte + */ + public byte getByte(String property, byte def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value instanceof Byte) { + return ((Byte)value).byteValue(); + } + throw new TypeException(property, value, "byte"); + } + + /** + * Returns the value of a short property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not a short + */ + public short getShort(String property, short def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value instanceof Short) { + return ((Short)value).shortValue(); + } + throw new TypeException(property, value, "short"); + } + + /** + * Returns the value of an integer property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not an integer + */ + public int getInt(String property, int def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value instanceof Integer) { + return ((Integer)value).intValue(); + } + throw new TypeException(property, value, "int"); + } + + /** + * Returns the value of a long property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not a long + */ + public long getLong(String property, long def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value instanceof Long) { + return ((Long)value).longValue(); + } + throw new TypeException(property, value, "long"); + } + + /** + * Returns the value of a float property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not a float + */ + public float getFloat(String property, float def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value instanceof Float) { + return ((Float)value).floatValue(); + } + throw new TypeException(property, value, "float"); + } + + /** + * Returns the value of a double property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not a double + */ + public double getDouble(String property, double def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value instanceof Double) { + return ((Double)value).doubleValue(); + } + throw new TypeException(property, value, "double"); + } + + /** + * Returns the value of a string property, or the default if the property + * has not been defined. + * + * @param property The name of the property to return + * @param def The default value to return if the property is not set + * @return the value of the property + * @throws TypeException if the property is set and is not a string + */ + public String getString(String property, String def) { + Object value = super.get(property); + if (value == null) { + return def; + } + if (value == NULL_STRING) { + return null; + } else if (value instanceof String) { + return (String)value; + } + throw new TypeException(property, value, "string"); + } + + /* + * Getters with implicit defaults + */ + + /** + * Returns the value of a boolean property, or false + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not a boolean + */ + public boolean getBoolean(String property) { + return getBoolean(property, false); + } + + /** + * Returns the value of a byte property, or 0 + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not a byte + */ + public byte getByte(String property) { + return getByte(property, (byte)0); + } + + /** + * Returns the value of a short property, or 0 + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not a short + */ + public short getShort(String property) { + return getShort(property, (short)0); + } + + /** + * Returns the value of an integer property, or 0 + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not an integer + */ + public int getInt(String property) { + return getInt(property, 0); + } + + /** + * Returns the value of a long property, or 0 + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not a long + */ + public long getLong(String property) { + return getLong(property, 0L); + } + + /** + * Returns the value of a float property, or 0.0 + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not a float + */ + public float getFloat(String property) { + return getFloat(property, 0.0f); + } + + /** + * Returns the value of a double property, or 0.0 + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not a double + */ + public double getDouble(String property) { + return getDouble(property, 0.0); + } + + /** + * Returns the value of a String property, or "" + * if the property has not been defined. + * + * @param property The name of the property to return + * @return the value of the property + * @throws TypeException if the property is set and is not a string + */ + public String getString(String property) { + return getString(property, ""); + } + + // Values returned by getStringInfo() + public static final int STRING_TYPE_MISMATCH = -2; + public static final int STRING_NOT_SET = -1; + public static final int STRING_NULL = 0; + public static final int STRING_SET = 1; + + /** + * Provides string type information about a property. + * + * @param property the property to check + * @return STRING_SET if the property is a string and is non-null. + * STRING_NULL if the property is a string and is null. + * STRING_NOT_SET if the property is not set (no type or value). + * STRING_TYPE_MISMATCH if the property is set but is not a string. + */ + public int getStringInfo(String property) { + Object value = super.get(property); + if (value == null) { + return STRING_NOT_SET; + } + if (value == NULL_STRING) { + return STRING_NULL; + } else if (value instanceof String) { + return STRING_SET; + } + return STRING_TYPE_MISMATCH; + } +} diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java index 6034a1e6e82d2d8caeef10cfa26eb80e6b2aad4e..b81c2b3527d65baa1d5ce41b710ead7f32c05d70 100644 --- a/core/java/com/android/internal/view/menu/IconMenuView.java +++ b/core/java/com/android/internal/view/menu/IconMenuView.java @@ -498,19 +498,23 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi @Override protected void onDraw(Canvas canvas) { - if (mHorizontalDivider != null) { + Drawable drawable = mHorizontalDivider; + if (drawable != null) { // If we have a horizontal divider to draw, draw it at the remembered positions - for (int i = mHorizontalDividerRects.size() - 1; i >= 0; i--) { - mHorizontalDivider.setBounds(mHorizontalDividerRects.get(i)); - mHorizontalDivider.draw(canvas); + final ArrayList rects = mHorizontalDividerRects; + for (int i = rects.size() - 1; i >= 0; i--) { + drawable.setBounds(rects.get(i)); + drawable.draw(canvas); } } - - if (mVerticalDivider != null) { + + drawable = mVerticalDivider; + if (drawable != null) { // If we have a vertical divider to draw, draw it at the remembered positions - for (int i = mVerticalDividerRects.size() - 1; i >= 0; i--) { - mVerticalDivider.setBounds(mVerticalDividerRects.get(i)); - mVerticalDivider.draw(canvas); + final ArrayList rects = mVerticalDividerRects; + for (int i = rects.size() - 1; i >= 0; i--) { + drawable.setBounds(rects.get(i)); + drawable.draw(canvas); } } } @@ -520,14 +524,12 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi } @Override - public LayoutParams generateLayoutParams(AttributeSet attrs) - { + public LayoutParams generateLayoutParams(AttributeSet attrs) { return new IconMenuView.LayoutParams(getContext(), attrs); } @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) - { + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { // Override to allow type-checking of LayoutParams. return p instanceof IconMenuView.LayoutParams; } diff --git a/core/java/com/google/android/net/GoogleHttpClient.java b/core/java/com/google/android/net/GoogleHttpClient.java index ac9ad733348e45c5baac4603fd3880764c28625b..871c925478e4f3931adb0bab304e720e2530ba75 100644 --- a/core/java/com/google/android/net/GoogleHttpClient.java +++ b/core/java/com/google/android/net/GoogleHttpClient.java @@ -196,6 +196,12 @@ public class GoogleHttpClient implements HttpClient { } } + public String rewriteURI(String original) { + UrlRules rules = UrlRules.getRules(mResolver); + UrlRules.Rule rule = rules.matchRule(original); + return rule.apply(original); + } + public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException { // Rewrite the supplied URL... @@ -262,7 +268,7 @@ public class GoogleHttpClient implements HttpClient { * * @param originalUserAgent to modify (however you identify yourself) * @return user agent with a "yes, I really can handle gzip" token added. - * @deprecated Use {@link #GoogleHttpClient(android.content.ContentResolver, String, boolean)} + * @deprecated Use {@link #GoogleHttpClient(android.content.ContentResolver, String, boolean)} */ public static String getGzipCapableUserAgent(String originalUserAgent) { return originalUserAgent + "; gzip"; diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 18f2878ad5ad1ad271667e7cce3e712301ee75b4..4839b6f1d991e9cfaefe6e63871c9f7c6c5718cc 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -21,6 +21,10 @@ LOCAL_SRC_FILES:= \ CursorWindow.cpp \ com_google_android_gles_jni_EGLImpl.cpp \ com_google_android_gles_jni_GLImpl.cpp.arm \ + android_opengl_GLES10.cpp \ + android_opengl_GLES10Ext.cpp \ + android_opengl_GLES11.cpp \ + android_opengl_GLES11Ext.cpp \ android_database_CursorWindow.cpp \ android_database_SQLiteDebug.cpp \ android_database_SQLiteDatabase.cpp \ @@ -112,7 +116,8 @@ LOCAL_SRC_FILES:= \ android_ddm_DdmHandleNativeHeap.cpp \ android_location_GpsLocationProvider.cpp \ com_android_internal_os_ZygoteInit.cpp \ - com_android_internal_graphics_NativeUtils.cpp + com_android_internal_graphics_NativeUtils.cpp \ + android_backup_FileBackupHelper.cpp LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ @@ -125,6 +130,7 @@ LOCAL_C_INCLUDES += \ external/skia/include/core \ external/skia/include/effects \ external/skia/include/images \ + external/skia/src/ports \ external/skia/include/utils \ external/sqlite/dist \ external/sqlite/android \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index f4643f4dbcd4f410d0783525ff7d3a75dd77923f..aa6450d153c23c854f5e9ae55e631d55b24bf37f 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -30,6 +30,7 @@ #include #include +#include #include "jni.h" #include "JNIHelp.h" @@ -66,6 +67,10 @@ extern int register_android_graphics_Typeface(JNIEnv* env); extern int register_com_google_android_gles_jni_EGLImpl(JNIEnv* env); extern int register_com_google_android_gles_jni_GLImpl(JNIEnv* env); +extern int register_android_opengl_jni_GLES10(JNIEnv* env); +extern int register_android_opengl_jni_GLES10Ext(JNIEnv* env); +extern int register_android_opengl_jni_GLES11(JNIEnv* env); +extern int register_android_opengl_jni_GLES11Ext(JNIEnv* env); extern int register_android_hardware_Camera(JNIEnv *env); @@ -150,6 +155,7 @@ 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); extern int register_android_location_GpsLocationProvider(JNIEnv* env); +extern int register_android_backup_FileBackupHelper(JNIEnv *env); static AndroidRuntime* gCurRuntime = NULL; @@ -224,6 +230,13 @@ AndroidRuntime::AndroidRuntime() // this sets our preference for 16bit images during decode // in case the src is opaque and 24bit SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config); + // This cache is shared between browser native images, and java "purgeable" + // bitmaps. This globalpool is for images that do not either use the java + // heap, or are not backed by ashmem. See BitmapFactory.cpp for the key + // java call site. + SkImageRef_GlobalPool::SetRAMBudget(512 * 1024); + // There is also a global font cache, but its budget is specified in code + // see SkFontHost_android.cpp // Pre-allocate enough space to hold a fair number of options. mOptions.setCapacity(20); @@ -1042,6 +1055,10 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_ViewRoot), REG_JNI(register_com_google_android_gles_jni_EGLImpl), REG_JNI(register_com_google_android_gles_jni_GLImpl), + REG_JNI(register_android_opengl_jni_GLES10), + REG_JNI(register_android_opengl_jni_GLES10Ext), + REG_JNI(register_android_opengl_jni_GLES11), + REG_JNI(register_android_opengl_jni_GLES11Ext), REG_JNI(register_android_graphics_Bitmap), REG_JNI(register_android_graphics_BitmapFactory), @@ -1109,6 +1126,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_ddm_DdmHandleNativeHeap), REG_JNI(register_android_util_Base64), REG_JNI(register_android_location_GpsLocationProvider), + REG_JNI(register_android_backup_FileBackupHelper), }; /* diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 332b01c7ce70546e8ee6d6a3abdf172e4a5e7c17..1fd15d687baf2b677a3666eaa2dabfe70742bf3c 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -1,6 +1,8 @@ #define LOG_TAG "BitmapFactory" #include "SkImageDecoder.h" +#include "SkImageRef_ashmem.h" +#include "SkImageRef_GlobalPool.h" #include "SkPixelRef.h" #include "SkStream.h" #include "GraphicsJNI.h" @@ -19,9 +21,12 @@ static jfieldID gOptions_justBoundsFieldID; static jfieldID gOptions_sampleSizeFieldID; static jfieldID gOptions_configFieldID; static jfieldID gOptions_ditherFieldID; +static jfieldID gOptions_purgeableFieldID; +static jfieldID gOptions_shareableFieldID; static jfieldID gOptions_widthFieldID; static jfieldID gOptions_heightFieldID; static jfieldID gOptions_mimeFieldID; +static jfieldID gOptions_mCancelID; static jclass gFileDescriptor_class; static jfieldID gFileDescriptor_descriptor; @@ -32,8 +37,6 @@ static jfieldID gFileDescriptor_descriptor; #define TRACE_BITMAP(code) #endif -//#define MIN_SIZE_TO_USE_MMAP (4*1024) - /////////////////////////////////////////////////////////////////////////////// class AutoDecoderCancel { @@ -204,12 +207,16 @@ class AssetStreamAdaptor : public SkStream { public: AssetStreamAdaptor(Asset* a) : fAsset(a) {} - virtual bool rewind() { + virtual bool rewind() { off_t pos = fAsset->seek(0, SEEK_SET); - return pos != (off_t)-1; + if (pos == (off_t)-1) { + SkDebugf("----- fAsset->seek(rewind) failed\n"); + return false; + } + return true; } - virtual size_t read(void* buffer, size_t size) { + virtual size_t read(void* buffer, size_t size) { ssize_t amount; if (NULL == buffer) { @@ -221,15 +228,20 @@ public: off_t oldOffset = fAsset->seek(0, SEEK_CUR); if (-1 == oldOffset) { + SkDebugf("---- fAsset->seek(oldOffset) failed\n"); return 0; } off_t newOffset = fAsset->seek(size, SEEK_CUR); if (-1 == newOffset) { + SkDebugf("---- fAsset->seek(%d) failed\n", size); return 0; } amount = newOffset - oldOffset; } else { amount = fAsset->read(buffer, size); + if (amount <= 0) { + SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount); + } } if (amount < 0) { @@ -278,13 +290,46 @@ static jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) { return jstr; } -static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, - jobject options) { +static bool optionsPurgeable(JNIEnv* env, jobject options) { + return options != NULL && + env->GetBooleanField(options, gOptions_purgeableFieldID); +} + +static bool optionsShareable(JNIEnv* env, jobject options) { + return options != NULL && + env->GetBooleanField(options, gOptions_shareableFieldID); +} + +static jobject nullObjectReturn(const char msg[]) { + if (msg) { + SkDebugf("--- %s\n", msg); + } + return NULL; +} + +static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream, + int sampleSize) { + SkPixelRef* pr; + // only use ashmem for large images, since mmaps come at a price + if (bitmap->getSize() >= 32 * 65536) { + pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize); + } else { + pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize); + } + bitmap->setPixelRef(pr)->unref(); + return pr; +} +// since we "may" create a purgeable imageref, we require the stream be ref'able +// i.e. dynamically allocated, since its lifetime may exceed the current stack +// frame. +static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, + jobject options, bool allowPurgeable) { int sampleSize = 1; SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; SkBitmap::Config prefConfig = SkBitmap::kNo_Config; bool doDither = true; + bool isPurgeable = allowPurgeable && optionsPurgeable(env, options); if (NULL != options) { sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); @@ -303,14 +348,14 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, SkImageDecoder* decoder = SkImageDecoder::Factory(stream); if (NULL == decoder) { - return NULL; + return nullObjectReturn("SkImageDecoder::Factory returned null"); } decoder->setSampleSize(sampleSize); decoder->setDitherImage(doDither); NinePatchPeeker peeker; - JavaPixelAllocator allocator(env); + JavaPixelAllocator javaAllocator(env); SkBitmap* bitmap = new SkBitmap; Res_png_9patch dummy9Patch; @@ -318,14 +363,27 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, SkAutoTDelete adb(bitmap); decoder->setPeeker(&peeker); - decoder->setAllocator(&allocator); - + if (!isPurgeable) { + decoder->setAllocator(&javaAllocator); + } + AutoDecoderCancel adc(options, decoder); - if (!decoder->decode(stream, bitmap, prefConfig, mode)) { - return NULL; + // To fix the race condition in case "requestCancelDecode" + // happens earlier than AutoDecoderCancel object is added + // to the gAutoDecoderCancelMutex linked list. + if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) { + return nullObjectReturn("gOptions_mCancelID");; } - + + SkImageDecoder::Mode decodeMode = mode; + if (isPurgeable) { + decodeMode = SkImageDecoder::kDecodeBounds_Mode; + } + if (!decoder->decode(stream, bitmap, prefConfig, decodeMode)) { + return nullObjectReturn("decoder->decode returned false"); + } + // update options (if any) if (NULL != options) { env->SetIntField(options, gOptions_widthFieldID, bitmap->width()); @@ -336,7 +394,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, env->SetObjectField(options, gOptions_mimeFieldID, getMimeTypeString(env, decoder->getFormat())); } - + // if we're in justBounds mode, return now (skip the java bitmap) if (SkImageDecoder::kDecodeBounds_Mode == mode) { return NULL; @@ -347,12 +405,12 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, size_t ninePatchArraySize = peeker.fPatch->serializedSize(); ninePatchChunk = env->NewByteArray(ninePatchArraySize); if (NULL == ninePatchChunk) { - return NULL; + return nullObjectReturn("ninePatchChunk == null"); } jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk, NULL); if (NULL == array) { - return NULL; + return nullObjectReturn("primitive array == null"); } peeker.fPatch->serialize(array); env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); @@ -372,12 +430,18 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1); } } - - // promise we will never change our pixels (great for sharing and pictures) - SkPixelRef* ref = bitmap->pixelRef(); - SkASSERT(ref); - ref->setImmutable(); + SkPixelRef* pr; + if (isPurgeable) { + pr = installPixelRef(bitmap, stream, sampleSize); + } else { + // if we get here, we're in kDecodePixels_Mode and will therefore + // already have a pixelref installed. + pr = bitmap->pixelRef(); + } + // promise we will never change our pixels (great for sharing and pictures) + pr->setImmutable(); + // now create the java bitmap return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk); } @@ -390,7 +454,8 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage); if (stream) { - bitmap = doDecode(env, stream, padding, options); + // for now we don't allow purgeable with java inputstreams + bitmap = doDecode(env, stream, padding, options, false); stream->unref(); } return bitmap; @@ -431,52 +496,96 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jint descriptor = env->GetIntField(fileDescriptor, gFileDescriptor_descriptor); - -#ifdef MIN_SIZE_TO_USE_MMAP - // First try to use mmap - size_t size = getFDSize(descriptor); - if (size >= MIN_SIZE_TO_USE_MMAP) { - void* addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, descriptor, 0); -// SkDebugf("-------- mmap returned %p %d\n", addr, size); - if (MAP_FAILED != addr) { - SkMemoryStream strm(addr, size); - jobject obj = doDecode(env, &strm, padding, bitmapFactoryOptions); - munmap(addr, size); - return obj; + + bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions); + bool isShareable = optionsShareable(env, bitmapFactoryOptions); + bool weOwnTheFD = false; + if (isPurgeable && isShareable) { + int newFD = ::dup(descriptor); + if (-1 != newFD) { + weOwnTheFD = true; + descriptor = newFD; } } -#endif - // we pass false for closeWhenDone, since the caller owns the descriptor - SkFDStream file(descriptor, false); - if (!file.isValid()) { + SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD); + SkAutoUnref aur(stream); + if (!stream->isValid()) { return NULL; } - - /* Restore our offset when we leave, so the caller doesn't have to. - This is a real feature, so we can be called more than once with the - same descriptor. + + /* Restore our offset when we leave, so we can be called more than once + with the same descriptor. This is only required if we didn't dup the + file descriptor, but it is OK to do it all the time. */ AutoFDSeek as(descriptor); - return doDecode(env, &file, padding, bitmapFactoryOptions); + return doDecode(env, stream, padding, bitmapFactoryOptions, true); +} + +/* make a deep copy of the asset, and return it as a stream, or NULL if there + was an error. + */ +static SkStream* copyAssetToStream(Asset* asset) { + // if we could "ref/reopen" the asset, we may not need to copy it here + off_t size = asset->seek(0, SEEK_SET); + if ((off_t)-1 == size) { + SkDebugf("---- copyAsset: asset rewind failed\n"); + return NULL; + } + + size = asset->getLength(); + if (size <= 0) { + SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size); + return NULL; + } + + SkStream* stream = new SkMemoryStream(size); + void* data = const_cast(stream->getMemoryBase()); + off_t len = asset->read(data, size); + if (len != size) { + SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len); + delete stream; + stream = NULL; + } + return stream; } static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jint native_asset, // Asset jobject padding, // Rect jobject options) { // BitmapFactory$Options - AssetStreamAdaptor mystream((Asset*)native_asset); - - return doDecode(env, &mystream, padding, options); + SkStream* stream; + Asset* asset = reinterpret_cast(native_asset); + + if (optionsPurgeable(env, options)) { + // if we could "ref/reopen" the asset, we may not need to copy it here + // and we could assume optionsShareable, since assets are always RO + stream = copyAssetToStream(asset); + if (NULL == stream) { + return NULL; + } + } else { + // since we know we'll be done with the asset when we return, we can + // just use a simple wrapper + stream = new AssetStreamAdaptor(asset); + } + SkAutoUnref aur(stream); + return doDecode(env, stream, padding, options, true); } static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, int offset, int length, jobject options) { - AutoJavaByteArray ar(env, byteArray); - SkMemoryStream stream(ar.ptr() + offset, length); - - return doDecode(env, &stream, NULL, options); + /* If optionsShareable() we could decide to just wrap the java array and + share it, but that means adding a globalref to the java array object + and managing its lifetime. For now we just always copy the array's data + if optionsPurgeable(). + */ + AutoJavaByteArray ar(env, byteArray); + SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, + optionsPurgeable(env, options)); + SkAutoUnref aur(stream); + return doDecode(env, stream, NULL, options, true); } static void nativeRequestCancel(JNIEnv*, jobject joptions) { @@ -585,9 +694,12 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig", "Landroid/graphics/Bitmap$Config;"); gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z"); + gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z"); + gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z"); gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I"); gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I"); gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;"); + gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z"); gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor"); gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I"); diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 605e4b8af76dfc5aed1e7874f71df253b9282ad2..93d68cbfe0aeabca9577c925d9b6191ea12eec2c 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -21,6 +21,8 @@ #include "SkCanvas.h" #include "SkDevice.h" #include "SkGLCanvas.h" +#include "SkGraphics.h" +#include "SkImageRef_GlobalPool.h" #include "SkShader.h" #include "SkTemplates.h" @@ -58,8 +60,11 @@ public: return new SkGLCanvas; } - static void freeGlCaches(JNIEnv* env, jobject) { + static void freeCaches(JNIEnv* env, jobject) { + // these are called in no particular order SkGLCanvas::DeleteAllTextures(); + SkImageRef_GlobalPool::SetRAMUsed(0); + SkGraphics::SetFontCacheUsed(0); } static jboolean isOpaque(JNIEnv* env, jobject jcanvas) { @@ -717,8 +722,7 @@ public: jsize textCount = env->GetArrayLength(text); SkScalar x_ = SkFloatToScalar(x); SkScalar y_ = SkFloatToScalar(y); - textArray += index; - canvas->drawText(textArray, count << 1, x_, y_, *paint); + canvas->drawText(textArray + index, count << 1, x_, y_, *paint); env->ReleaseCharArrayElements(text, textArray, 0); } @@ -762,8 +766,7 @@ public: posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]); posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]); } - textArray += index; - canvas->drawPosText(textArray, count << 1, posPtr, *paint); + canvas->drawPosText(textArray + index, count << 1, posPtr, *paint); if (text) { env->ReleaseCharArrayElements(text, textArray, 0); } @@ -933,7 +936,7 @@ static JNINativeMethod gCanvasMethods[] = { (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture}, - {"freeGlCaches", "()V", (void*) SkCanvasGlue::freeGlCaches} + {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches} }; #include diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index 00d6cd9767f8d8b7a0d581649bd4c53540571f15..1dc031472b2130948a442c73ad0784ce090c6b73 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -102,6 +102,36 @@ static void Region_translate(JNIEnv* env, jobject region, int x, int y, jobject rgn->translate(x, y); } +// Scale the rectangle by given scale and set the reuslt to the dst. +static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) { + dst->fLeft = (int)::roundf(src.fLeft * scale); + dst->fTop = (int)::roundf(src.fTop * scale); + dst->fRight = (int)::roundf(src.fRight * scale); + dst->fBottom = (int)::roundf(src.fBottom * scale); +} + +// Scale the region by given scale and set the reuslt to the dst. +// dest and src can be the same region instance. +static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) { + SkRegion tmp; + SkRegion::Iterator iter(src); + + for (; !iter.done(); iter.next()) { + SkIRect r; + scale_rect(&r, iter.rect(), scale); + tmp.op(r, SkRegion::kUnion_Op); + } + dst->swap(tmp); +} + +static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) { + SkRegion* rgn = GetSkRegion(env, region); + if (dst) + scale_rgn(GetSkRegion(env, dst), *rgn, scale); + else + scale_rgn(rgn, *rgn, scale); +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "Parcel.h" @@ -139,6 +169,13 @@ static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, const SkRegion* //////////////////////////////////////////////////////////////////////////////////////////////////////////// +static jboolean Region_equals(JNIEnv* env, jobject clazz, const SkRegion *r1, const SkRegion* r2) +{ + return (jboolean) (*r1 == *r2); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + struct RgnIterPair { SkRegion fRgn; // a copy of the caller's region SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn) @@ -206,10 +243,12 @@ static JNINativeMethod gRegionMethods[] = { { "quickContains", "(IIII)Z", (void*)Region_quickContains }, { "quickReject", "(IIII)Z", (void*)Region_quickRejectIIII }, { "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn }, + { "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale }, { "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate }, // parceling methods { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I", (void*)Region_createFromParcel }, - { "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel } + { "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel }, + { "nativeEquals", "(II)Z", (void*)Region_equals }, }; int register_android_graphics_Region(JNIEnv* env); diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index e9514317b8f3c7280bb2c63bcf177e132495da4e..21dde63952861617304bb50b461617114c30d4b2 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -133,6 +133,14 @@ static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject, return SkTypeface::CreateFromStream(new AssetStream(asset, true)); } +static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) { + NPE_CHECK_RETURN_ZERO(env, jpath); + + AutoJavaStringToUTF8 str(env, jpath); + + return SkTypeface::CreateFromFile(str.c_str()); +} + /////////////////////////////////////////////////////////////////////////////// static JNINativeMethod gTypefaceMethods[] = { @@ -140,9 +148,10 @@ static JNINativeMethod gTypefaceMethods[] = { { "nativeCreateFromTypeface", "(II)I", (void*)Typeface_createFromTypeface }, { "nativeUnref", "(I)V", (void*)Typeface_unref }, { "nativeGetStyle", "(I)I", (void*)Typeface_getStyle }, - { "nativeCreateFromAsset", - "(Landroid/content/res/AssetManager;Ljava/lang/String;)I", - (void*)Typeface_createFromAsset } + { "nativeCreateFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)I", + (void*)Typeface_createFromAsset }, + { "nativeCreateFromFile", "(Ljava/lang/String;)I", + (void*)Typeface_createFromFile } }; int register_android_graphics_Typeface(JNIEnv* env); @@ -153,4 +162,3 @@ int register_android_graphics_Typeface(JNIEnv* env) gTypefaceMethods, SK_ARRAY_COUNT(gTypefaceMethods)); } - diff --git a/core/jni/android_backup_FileBackupHelper.cpp b/core/jni/android_backup_FileBackupHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6de3a52f69b0a3308c337fb48bf7ce330dfbe37 --- /dev/null +++ b/core/jni/android_backup_FileBackupHelper.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FileBackupHelper_native" +#include + +#include "JNIHelp.h" +#include + +#include + +namespace android +{ + +static jfieldID s_descriptorField = 0; + +static int +performBackup_native(JNIEnv* env, jobject clazz, jstring basePath, jobject oldState, jobject data, + jobject newState, jobjectArray files) +{ + int err; + + // all parameters have already been checked against null + LOGD("oldState=%p newState=%p data=%p\n", oldState, newState, data); + int oldStateFD = oldState != NULL ? env->GetIntField(oldState, s_descriptorField) : -1; + int newStateFD = env->GetIntField(newState, s_descriptorField); + int dataFD = env->GetIntField(data, s_descriptorField); + + char const* basePathUTF = env->GetStringUTFChars(basePath, NULL); + LOGD("basePathUTF=\"%s\"\n", basePathUTF); + const int fileCount = env->GetArrayLength(files); + char const** filesUTF = (char const**)malloc(sizeof(char*)*fileCount); + for (int i=0; iGetStringUTFChars((jstring)env->GetObjectArrayElement(files, i), NULL); + } + + err = back_up_files(oldStateFD, dataFD, newStateFD, basePathUTF, filesUTF, fileCount); + + for (int i=0; iReleaseStringUTFChars((jstring)env->GetObjectArrayElement(files, i), filesUTF[i]); + } + free(filesUTF); + env->ReleaseStringUTFChars(basePath, basePathUTF); + + return err; +} + +static const JNINativeMethod g_methods[] = { + { "performBackup_native", + "(Ljava/lang/String;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;" + "Ljava/io/FileDescriptor;[Ljava/lang/String;)I", + (void*)performBackup_native }, +}; + +int register_android_backup_FileBackupHelper(JNIEnv* env) +{ + LOGD("register_android_backup_FileBackupHelper"); + + jclass clazz; + + clazz = env->FindClass("java/io/FileDescriptor"); + LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor"); + s_descriptorField = env->GetFieldID(clazz, "descriptor", "I"); + LOG_FATAL_IF(s_descriptorField == NULL, + "Unable to find descriptor field in java.io.FileDescriptor"); + + return AndroidRuntime::registerNativeMethods(env, "android/backup/FileBackupHelper", + g_methods, NELEM(g_methods)); +} + +} diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp index c81af1cea91704a77adfc76c8e85665ff1bd68fd..0b8a604fea54907ff0ec151aea82b495675172fe 100644 --- a/core/jni/android_bluetooth_common.cpp +++ b/core/jni/android_bluetooth_common.cpp @@ -46,8 +46,9 @@ jfieldID get_field(JNIEnv *env, jclass clazz, const char *member, } typedef struct { - void (*user_cb)(DBusMessage *, void *); + void (*user_cb)(DBusMessage *, void *, void *); void *user; + void *nat; JNIEnv *env; } dbus_async_call_t; @@ -63,7 +64,7 @@ void dbus_func_args_async_callback(DBusPendingCall *call, void *data) { if (msg) { if (req->user_cb) { // The user may not deref the message object. - req->user_cb(msg, req->user); + req->user_cb(msg, req->user, req->nat); } dbus_message_unref(msg); } @@ -74,11 +75,14 @@ void dbus_func_args_async_callback(DBusPendingCall *call, void *data) { free(req); } -dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, +static dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, DBusConnection *conn, int timeout_ms, - void (*user_cb)(DBusMessage *, void *), + void (*user_cb)(DBusMessage *, + void *, + void*), void *user, + void *nat, const char *path, const char *ifc, const char *func, @@ -111,6 +115,7 @@ dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, pending->env = env; pending->user_cb = user_cb; pending->user = user; + pending->nat = nat; //pending->method = msg; reply = dbus_connection_send_with_reply(conn, msg, @@ -132,8 +137,9 @@ done: dbus_bool_t dbus_func_args_async(JNIEnv *env, DBusConnection *conn, int timeout_ms, - void (*reply)(DBusMessage *, void *), + void (*reply)(DBusMessage *, void *, void*), void *user, + void *nat, const char *path, const char *ifc, const char *func, @@ -144,7 +150,7 @@ dbus_bool_t dbus_func_args_async(JNIEnv *env, va_start(lst, first_arg_type); ret = dbus_func_args_async_valist(env, conn, timeout_ms, - reply, user, + reply, user, nat, path, ifc, func, first_arg_type, lst); va_end(lst); diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h index c30ba22a3318e57c6b4a7f814143d9b91f3fd2fc..69092ddb028df7ee1e8252120339ad482d128566 100644 --- a/core/jni/android_bluetooth_common.h +++ b/core/jni/android_bluetooth_common.h @@ -24,7 +24,9 @@ #include "utils/Log.h" #include +#include #include +#include #ifdef HAVE_BLUETOOTH #include @@ -45,6 +47,9 @@ namespace android { #define BTADDR_SIZE 18 // size of BT address character array (including null) +// size of the dbus event loops pollfd structure, hopefully never to be grown +#define DEFAULT_INITIAL_POLLFD_COUNT 8 + jfieldID get_field(JNIEnv *env, jclass clazz, const char *member, @@ -63,29 +68,33 @@ jfieldID get_field(JNIEnv *env, 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. */ + + /* protects the thread */ + pthread_mutex_t thread_mutex; + pthread_t thread; + /* our comms socket */ + /* mem for the list of sockets to listen to */ + struct pollfd *pollData; + int pollMemberCount; + int pollDataSize; + /* mem for matching set of dbus watch ptrs */ + DBusWatch **watchData; + /* pair of sockets for event loop control, Reader and Writer */ + int controlFdR; + int controlFdW; + /* our vm and env Version for future env generation */ + JavaVM *vm; + int envVer; + /* reference to our java self */ jobject me; - JNIEnv *env; }; -dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, - DBusConnection *conn, - int timeout_ms, - void (*reply)(DBusMessage *, void *), - void *user, - const char *path, - const char *ifc, - const char *func, - int first_arg_type, - va_list args); - dbus_bool_t dbus_func_args_async(JNIEnv *env, DBusConnection *conn, int timeout_ms, - void (*reply)(DBusMessage *, void *), + void (*reply)(DBusMessage *, void *, void *), void *user, + void *nat, const char *path, const char *ifc, const char *func, diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index f6cd211b20c4832cd66f88c1332d5ff2ad1124a3..c10799316b81d8d41089f1c33971f3a6a166c737 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -108,7 +108,8 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj sp camera = Camera::connect(); if (camera == NULL) { - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + jniThrowException(env, "java/lang/RuntimeException", + "Fail to connect to camera service"); return; } diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp index f0b35e977ef1c5cf49b334ba2ed332b2074ca76a..004b0e3ea07ebf68499755b0177f97dd80661a33 100644 --- a/core/jni/android_location_GpsLocationProvider.cpp +++ b/core/jni/android_location_GpsLocationProvider.cpp @@ -31,29 +31,33 @@ static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER; static jmethodID method_reportLocation; static jmethodID method_reportStatus; static jmethodID method_reportSvStatus; +static jmethodID method_reportAGpsStatus; static jmethodID method_xtraDownloadRequest; static const GpsInterface* sGpsInterface = NULL; static const GpsXtraInterface* sGpsXtraInterface = NULL; -static const GpsSuplInterface* sGpsSuplInterface = NULL; +static const AGpsInterface* sAGpsInterface = NULL; // data written to by GPS callbacks static GpsLocation sGpsLocation; static GpsStatus sGpsStatus; static GpsSvStatus sGpsSvStatus; +static AGpsStatus sAGpsStatus; // a copy of the data shared by android_location_GpsLocationProvider_wait_for_event // and android_location_GpsLocationProvider_read_status static GpsLocation sGpsLocationCopy; static GpsStatus sGpsStatusCopy; static GpsSvStatus sGpsSvStatusCopy; +static AGpsStatus sAGpsStatusCopy; enum CallbackType { kLocation = 1, kStatus = 2, kSvStatus = 4, - kXtraDownloadRequest = 8, - kDisableRequest = 16, + kAGpsStatus = 8, + kXtraDownloadRequest = 16, + kDisableRequest = 32, }; static int sPendingCallbacks; @@ -92,6 +96,17 @@ static void sv_status_callback(GpsSvStatus* sv_status) pthread_mutex_unlock(&sEventMutex); } +static void agps_status_callback(AGpsStatus* agps_status) +{ + pthread_mutex_lock(&sEventMutex); + + sPendingCallbacks |= kAGpsStatus; + memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus)); + + pthread_cond_signal(&sEventCond); + pthread_mutex_unlock(&sEventMutex); +} + GpsCallbacks sGpsCallbacks = { location_callback, status_callback, @@ -111,11 +126,15 @@ GpsXtraCallbacks sGpsXtraCallbacks = { download_request_callback, }; +AGpsCallbacks sAGpsCallbacks = { + agps_status_callback, +}; static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); + method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V"); method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); } @@ -129,7 +148,14 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o { if (!sGpsInterface) sGpsInterface = gps_get_interface(); - return (sGpsInterface && sGpsInterface->init(&sGpsCallbacks) == 0); + if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) + return false; + + if (!sAGpsInterface) + sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); + if (sAGpsInterface) + sAGpsInterface->init(&sAGpsCallbacks); + return true; } static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj) @@ -161,12 +187,6 @@ static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject o return (sGpsInterface->stop() == 0); } -static void android_location_GpsLocationProvider_set_fix_frequency(JNIEnv* env, jobject obj, jint fixFrequency) -{ - if (sGpsInterface->set_fix_frequency) - sGpsInterface->set_fix_frequency(fixFrequency); -} - static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) { sGpsInterface->delete_aiding_data(flags); @@ -186,6 +206,7 @@ static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, job memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy)); memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy)); memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy)); + memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy)); pthread_mutex_unlock(&sEventMutex); if (pendingCallbacks & kLocation) { @@ -201,6 +222,9 @@ static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, job if (pendingCallbacks & kSvStatus) { env->CallVoidMethod(obj, method_reportSvStatus); } + if (pendingCallbacks & kAGpsStatus) { + env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status); + } if (pendingCallbacks & kXtraDownloadRequest) { env->CallVoidMethod(obj, method_xtraDownloadRequest); } @@ -269,51 +293,72 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j env->ReleaseByteArrayElements(data, bytes, 0); } -static void android_location_GpsLocationProvider_set_supl_server(JNIEnv* env, jobject obj, - jint addr, jint port) +static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) { - if (!sGpsSuplInterface) { - sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE); + if (!sAGpsInterface) { + sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); } - if (sGpsSuplInterface) { - sGpsSuplInterface->set_server(addr, port); - } -} - -static void android_location_GpsLocationProvider_set_supl_apn(JNIEnv* env, jobject obj, jstring apn) -{ - if (!sGpsSuplInterface) { - sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE); - } - if (sGpsSuplInterface) { + if (sAGpsInterface) { if (apn == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } const char *apnStr = env->GetStringUTFChars(apn, NULL); - sGpsSuplInterface->set_apn(apnStr); + sAGpsInterface->data_conn_open(apnStr); env->ReleaseStringUTFChars(apn, apnStr); } } +static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) +{ + if (!sAGpsInterface) { + sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); + } + if (sAGpsInterface) { + sAGpsInterface->data_conn_closed(); + } +} + +static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) +{ + if (!sAGpsInterface) { + sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); + } + if (sAGpsInterface) { + sAGpsInterface->data_conn_failed(); + } +} + +static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, + jint type, jint addr, jint port) +{ + if (!sAGpsInterface) { + sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); + } + if (sAGpsInterface) { + sAGpsInterface->set_server(type, addr, port); + } +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, - {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, - {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}, - {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable}, - {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup}, - {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start}, - {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop}, - {"native_set_fix_frequency", "(I)V", (void*)android_location_GpsLocationProvider_set_fix_frequency}, - {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data}, - {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event}, - {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status}, - {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time}, - {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, - {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, - {"native_set_supl_server", "(II)V", (void*)android_location_GpsLocationProvider_set_supl_server}, - {"native_set_supl_apn", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_set_supl_apn}, + {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, + {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}, + {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable}, + {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup}, + {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start}, + {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop}, + {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data}, + {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event}, + {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status}, + {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time}, + {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, + {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, + {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, + {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed}, + {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed}, + {"native_set_agps_server", "(III)V", (void*)android_location_GpsLocationProvider_set_agps_server}, }; int register_android_location_GpsLocationProvider(JNIEnv* env) diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index b8d6586d4db2ba4de6fa4892a3652cd1c90f64d5..42ada5450744ad48011b8671bb6ff8e3f0c6d41a 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -335,7 +335,7 @@ android_media_AudioTrack_start(JNIEnv *env, jobject thiz) jniThrowException(env, "java/lang/IllegalStateException", "Unable to retrieve AudioTrack pointer for start()"); } - + lpTrack->start(); } @@ -432,6 +432,45 @@ static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) } +// ---------------------------------------------------------------------------- +jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data, + jint offsetInBytes, jint sizeInBytes) { + // 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 (pTrack->sharedBuffer() == 0) { + written = pTrack->write(data + offsetInBytes, sizeInBytes); + } else { + if (audioFormat == javaAudioTrackFields.PCM16) { + // writing to shared memory, check for capacity + if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) { + sizeInBytes = pTrack->sharedBuffer()->size(); + } + memcpy(pTrack->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes); + written = sizeInBytes; + } else if (audioFormat == javaAudioTrackFields.PCM8) { + // data contains 8bit data we need to expand to 16bit before copying + // to the shared memory + // writing to shared memory, check for capacity, + // note that input data will occupy 2X the input space due to 8 to 16bit conversion + if (((size_t)sizeInBytes)*2 > pTrack->sharedBuffer()->size()) { + sizeInBytes = pTrack->sharedBuffer()->size() / 2; + } + int count = sizeInBytes; + int16_t *dst = (int16_t *)pTrack->sharedBuffer()->pointer(); + const int8_t *src = (const int8_t *)(data + offsetInBytes); + while(count--) { + *dst++ = (int16_t)(*src++^0x80) << 8; + } + // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide + // the 8bit mixer restriction from the user of this function + written = sizeInBytes; + } + } + return written; + +} + // ---------------------------------------------------------------------------- static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz, jbyteArray javaAudioData, @@ -461,35 +500,13 @@ static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz, 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 { - if (javaAudioFormat == javaAudioTrackFields.PCM16) { - memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes); - written = sizeInBytes; - } else if (javaAudioFormat == javaAudioTrackFields.PCM8) { - // cAudioData contains 8bit data we need to expand to 16bit before copying - // to the shared memory - int count = sizeInBytes; - int16_t *dst = (int16_t *)lpTrack->sharedBuffer()->pointer(); - const int8_t *src = (const int8_t *)(cAudioData + offsetInBytes); - while(count--) { - *dst++ = (int16_t)(*src++^0x80) << 8; - } - // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide - // the 8bit mixer restriction from the user of this function - written = sizeInBytes; - } - } + jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, 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; + return written; } diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index fcab8130d4b3d24a97647dac35ff813fc88067e7..25670df9d3739db8505169f8f15719bf65ac9603 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -291,6 +291,7 @@ static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject clazz { return doBooleanCommand("DRIVER RXFILTER-ADD 0", "OK") && doBooleanCommand("DRIVER RXFILTER-ADD 1", "OK") + && doBooleanCommand("DRIVER RXFILTER-ADD 3", "OK") && doBooleanCommand("DRIVER RXFILTER-START", "OK"); } @@ -298,6 +299,7 @@ static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject clazz) { jboolean result = doBooleanCommand("DRIVER RXFILTER-STOP", "OK"); if (result) { + (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 3", "OK"); (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 1", "OK"); (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 0", "OK"); } diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp new file mode 100644 index 0000000000000000000000000000000000000000..482d8eb1b88bd87e2f726a72e4df466faa8d6a3b --- /dev/null +++ b/core/jni/android_opengl_GLES10.cpp @@ -0,0 +1,3556 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +/* special calls implemented in Android's GLES wrapper used to more + * efficiently bound-check passed arrays */ +extern "C" { +GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, + const GLvoid *ptr, GLsizei count); +GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, + const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +} + +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. */ + +static 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); +} + +static int +getNumCompressedTextureFormats() { + int numCompressedTextureFormats = 0; + glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedTextureFormats); + return numCompressedTextureFormats; +} + +// -------------------------------------------------------------------------- + +/* void glActiveTexture ( GLenum texture ) */ +static void +android_glActiveTexture__I + (JNIEnv *_env, jobject _this, jint texture) { + glActiveTexture( + (GLenum)texture + ); +} + +/* void glAlphaFunc ( GLenum func, GLclampf ref ) */ +static void +android_glAlphaFunc__IF + (JNIEnv *_env, jobject _this, jint func, jfloat ref) { + glAlphaFunc( + (GLenum)func, + (GLclampf)ref + ); +} + +/* void glAlphaFuncx ( GLenum func, GLclampx ref ) */ +static void +android_glAlphaFuncx__II + (JNIEnv *_env, jobject _this, jint func, jint ref) { + glAlphaFuncx( + (GLenum)func, + (GLclampx)ref + ); +} + +/* void glBindTexture ( GLenum target, GLuint texture ) */ +static void +android_glBindTexture__II + (JNIEnv *_env, jobject _this, jint target, jint texture) { + glBindTexture( + (GLenum)target, + (GLuint)texture + ); +} + +/* void glBlendFunc ( GLenum sfactor, GLenum dfactor ) */ +static void +android_glBlendFunc__II + (JNIEnv *_env, jobject _this, jint sfactor, jint dfactor) { + glBlendFunc( + (GLenum)sfactor, + (GLenum)dfactor + ); +} + +/* void glClear ( GLbitfield mask ) */ +static void +android_glClear__I + (JNIEnv *_env, jobject _this, jint mask) { + glClear( + (GLbitfield)mask + ); +} + +/* void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) */ +static void +android_glClearColor__FFFF + (JNIEnv *_env, jobject _this, jfloat red, jfloat green, jfloat blue, jfloat alpha) { + glClearColor( + (GLclampf)red, + (GLclampf)green, + (GLclampf)blue, + (GLclampf)alpha + ); +} + +/* void glClearColorx ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) */ +static void +android_glClearColorx__IIII + (JNIEnv *_env, jobject _this, jint red, jint green, jint blue, jint alpha) { + glClearColorx( + (GLclampx)red, + (GLclampx)green, + (GLclampx)blue, + (GLclampx)alpha + ); +} + +/* void glClearDepthf ( GLclampf depth ) */ +static void +android_glClearDepthf__F + (JNIEnv *_env, jobject _this, jfloat depth) { + glClearDepthf( + (GLclampf)depth + ); +} + +/* void glClearDepthx ( GLclampx depth ) */ +static void +android_glClearDepthx__I + (JNIEnv *_env, jobject _this, jint depth) { + glClearDepthx( + (GLclampx)depth + ); +} + +/* void glClearStencil ( GLint s ) */ +static void +android_glClearStencil__I + (JNIEnv *_env, jobject _this, jint s) { + glClearStencil( + (GLint)s + ); +} + +/* void glClientActiveTexture ( GLenum texture ) */ +static void +android_glClientActiveTexture__I + (JNIEnv *_env, jobject _this, jint texture) { + glClientActiveTexture( + (GLenum)texture + ); +} + +/* void glColor4f ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) */ +static void +android_glColor4f__FFFF + (JNIEnv *_env, jobject _this, jfloat red, jfloat green, jfloat blue, jfloat alpha) { + glColor4f( + (GLfloat)red, + (GLfloat)green, + (GLfloat)blue, + (GLfloat)alpha + ); +} + +/* void glColor4x ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) */ +static void +android_glColor4x__IIII + (JNIEnv *_env, jobject _this, jint red, jint green, jint blue, jint alpha) { + glColor4x( + (GLfixed)red, + (GLfixed)green, + (GLfixed)blue, + (GLfixed)alpha + ); +} + +/* void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ) */ +static void +android_glColorMask__ZZZZ + (JNIEnv *_env, jobject _this, jboolean red, jboolean green, jboolean blue, jboolean alpha) { + glColorMask( + (GLboolean)red, + (GLboolean)green, + (GLboolean)blue, + (GLboolean)alpha + ); +} + +/* void glColorPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */ +static void +android_glColorPointerBounds__IIILjava_nio_Buffer_2I + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pointer = (GLvoid *) 0; + + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } + glColorPointerBounds( + (GLint)size, + (GLenum)type, + (GLsizei)stride, + (GLvoid *)pointer, + (GLsizei)remaining + ); +} + +/* void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) */ +static void +android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint imageSize, jobject data_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *data = (GLvoid *) 0; + + data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining); + glCompressedTexImage2D( + (GLenum)target, + (GLint)level, + (GLenum)internalformat, + (GLsizei)width, + (GLsizei)height, + (GLint)border, + (GLsizei)imageSize, + (GLvoid *)data + ); + if (_array) { + releasePointer(_env, _array, data, JNI_FALSE); + } +} + +/* void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) */ +static void +android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint imageSize, jobject data_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *data = (GLvoid *) 0; + + data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining); + glCompressedTexSubImage2D( + (GLenum)target, + (GLint)level, + (GLint)xoffset, + (GLint)yoffset, + (GLsizei)width, + (GLsizei)height, + (GLenum)format, + (GLsizei)imageSize, + (GLvoid *)data + ); + if (_array) { + releasePointer(_env, _array, data, JNI_FALSE); + } +} + +/* void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) */ +static void +android_glCopyTexImage2D__IIIIIIII + (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint x, jint y, jint width, jint height, jint border) { + 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 ) */ +static void +android_glCopyTexSubImage2D__IIIIIIII + (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint x, jint y, jint width, jint height) { + glCopyTexSubImage2D( + (GLenum)target, + (GLint)level, + (GLint)xoffset, + (GLint)yoffset, + (GLint)x, + (GLint)y, + (GLsizei)width, + (GLsizei)height + ); +} + +/* void glCullFace ( GLenum mode ) */ +static void +android_glCullFace__I + (JNIEnv *_env, jobject _this, jint mode) { + glCullFace( + (GLenum)mode + ); +} + +/* void glDeleteTextures ( GLsizei n, const GLuint *textures ) */ +static void +android_glDeleteTextures__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray textures_ref, jint offset) { + GLuint *textures_base = (GLuint *) 0; + jint _remaining; + GLuint *textures = (GLuint *) 0; + + if (!textures_ref) { + _env->ThrowNew(IAEClass, "textures == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(textures_ref) - offset; + if (_remaining < n) { + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + textures_base = (GLuint *) + _env->GetPrimitiveArrayCritical(textures_ref, (jboolean *)0); + textures = textures_base + offset; + + glDeleteTextures( + (GLsizei)n, + (GLuint *)textures + ); + +exit: + if (textures_base) { + _env->ReleasePrimitiveArrayCritical(textures_ref, textures_base, + JNI_ABORT); + } +} + +/* void glDeleteTextures ( GLsizei n, const GLuint *textures ) */ +static void +android_glDeleteTextures__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject textures_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLuint *textures = (GLuint *) 0; + + textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining); + if (_remaining < n) { + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glDeleteTextures( + (GLsizei)n, + (GLuint *)textures + ); + +exit: + if (_array) { + releasePointer(_env, _array, textures, JNI_FALSE); + } +} + +/* void glDepthFunc ( GLenum func ) */ +static void +android_glDepthFunc__I + (JNIEnv *_env, jobject _this, jint func) { + glDepthFunc( + (GLenum)func + ); +} + +/* void glDepthMask ( GLboolean flag ) */ +static void +android_glDepthMask__Z + (JNIEnv *_env, jobject _this, jboolean flag) { + glDepthMask( + (GLboolean)flag + ); +} + +/* void glDepthRangef ( GLclampf zNear, GLclampf zFar ) */ +static void +android_glDepthRangef__FF + (JNIEnv *_env, jobject _this, jfloat zNear, jfloat zFar) { + glDepthRangef( + (GLclampf)zNear, + (GLclampf)zFar + ); +} + +/* void glDepthRangex ( GLclampx zNear, GLclampx zFar ) */ +static void +android_glDepthRangex__II + (JNIEnv *_env, jobject _this, jint zNear, jint zFar) { + glDepthRangex( + (GLclampx)zNear, + (GLclampx)zFar + ); +} + +/* void glDisable ( GLenum cap ) */ +static void +android_glDisable__I + (JNIEnv *_env, jobject _this, jint cap) { + glDisable( + (GLenum)cap + ); +} + +/* void glDisableClientState ( GLenum array ) */ +static void +android_glDisableClientState__I + (JNIEnv *_env, jobject _this, jint array) { + glDisableClientState( + (GLenum)array + ); +} + +/* void glDrawArrays ( GLenum mode, GLint first, GLsizei count ) */ +static void +android_glDrawArrays__III + (JNIEnv *_env, jobject _this, jint mode, jint first, jint count) { + glDrawArrays( + (GLenum)mode, + (GLint)first, + (GLsizei)count + ); +} + +/* void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) */ +static void +android_glDrawElements__IIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf) { + jarray _array = (jarray) 0; + jint _remaining; + 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); + } +} + +/* void glEnable ( GLenum cap ) */ +static void +android_glEnable__I + (JNIEnv *_env, jobject _this, jint cap) { + glEnable( + (GLenum)cap + ); +} + +/* void glEnableClientState ( GLenum array ) */ +static void +android_glEnableClientState__I + (JNIEnv *_env, jobject _this, jint array) { + glEnableClientState( + (GLenum)array + ); +} + +/* void glFinish ( void ) */ +static void +android_glFinish__ + (JNIEnv *_env, jobject _this) { + glFinish(); +} + +/* void glFlush ( void ) */ +static void +android_glFlush__ + (JNIEnv *_env, jobject _this) { + glFlush(); +} + +/* void glFogf ( GLenum pname, GLfloat param ) */ +static void +android_glFogf__IF + (JNIEnv *_env, jobject _this, jint pname, jfloat param) { + glFogf( + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glFogfv ( GLenum pname, const GLfloat *params ) */ +static void +android_glFogfv__I_3FI + (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_FOG_MODE) + case GL_FOG_MODE: +#endif // defined(GL_FOG_MODE) +#if defined(GL_FOG_DENSITY) + case GL_FOG_DENSITY: +#endif // defined(GL_FOG_DENSITY) +#if defined(GL_FOG_START) + case GL_FOG_START: +#endif // defined(GL_FOG_START) +#if defined(GL_FOG_END) + case GL_FOG_END: +#endif // defined(GL_FOG_END) + _needed = 1; + break; +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glFogfv( + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glFogfv ( GLenum pname, const GLfloat *params ) */ +static void +android_glFogfv__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_FOG_MODE) + case GL_FOG_MODE: +#endif // defined(GL_FOG_MODE) +#if defined(GL_FOG_DENSITY) + case GL_FOG_DENSITY: +#endif // defined(GL_FOG_DENSITY) +#if defined(GL_FOG_START) + case GL_FOG_START: +#endif // defined(GL_FOG_START) +#if defined(GL_FOG_END) + case GL_FOG_END: +#endif // defined(GL_FOG_END) + _needed = 1; + break; +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glFogfv( + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glFogx ( GLenum pname, GLfixed param ) */ +static void +android_glFogx__II + (JNIEnv *_env, jobject _this, jint pname, jint param) { + glFogx( + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glFogxv ( GLenum pname, const GLfixed *params ) */ +static void +android_glFogxv__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_FOG_MODE) + case GL_FOG_MODE: +#endif // defined(GL_FOG_MODE) +#if defined(GL_FOG_DENSITY) + case GL_FOG_DENSITY: +#endif // defined(GL_FOG_DENSITY) +#if defined(GL_FOG_START) + case GL_FOG_START: +#endif // defined(GL_FOG_START) +#if defined(GL_FOG_END) + case GL_FOG_END: +#endif // defined(GL_FOG_END) + _needed = 1; + break; +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glFogxv( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glFogxv ( GLenum pname, const GLfixed *params ) */ +static void +android_glFogxv__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_FOG_MODE) + case GL_FOG_MODE: +#endif // defined(GL_FOG_MODE) +#if defined(GL_FOG_DENSITY) + case GL_FOG_DENSITY: +#endif // defined(GL_FOG_DENSITY) +#if defined(GL_FOG_START) + case GL_FOG_START: +#endif // defined(GL_FOG_START) +#if defined(GL_FOG_END) + case GL_FOG_END: +#endif // defined(GL_FOG_END) + _needed = 1; + break; +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glFogxv( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glFrontFace ( GLenum mode ) */ +static void +android_glFrontFace__I + (JNIEnv *_env, jobject _this, jint mode) { + glFrontFace( + (GLenum)mode + ); +} + +/* void glFrustumf ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */ +static void +android_glFrustumf__FFFFFF + (JNIEnv *_env, jobject _this, jfloat left, jfloat right, jfloat bottom, jfloat top, jfloat zNear, jfloat zFar) { + 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 ) */ +static void +android_glFrustumx__IIIIII + (JNIEnv *_env, jobject _this, jint left, jint right, jint bottom, jint top, jint zNear, jint zFar) { + glFrustumx( + (GLfixed)left, + (GLfixed)right, + (GLfixed)bottom, + (GLfixed)top, + (GLfixed)zNear, + (GLfixed)zFar + ); +} + +/* void glGenTextures ( GLsizei n, GLuint *textures ) */ +static void +android_glGenTextures__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray textures_ref, jint offset) { + jint _exception = 0; + GLuint *textures_base = (GLuint *) 0; + jint _remaining; + GLuint *textures = (GLuint *) 0; + + if (!textures_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "textures == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(textures_ref) - offset; + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + textures_base = (GLuint *) + _env->GetPrimitiveArrayCritical(textures_ref, (jboolean *)0); + textures = textures_base + offset; + + glGenTextures( + (GLsizei)n, + (GLuint *)textures + ); + +exit: + if (textures_base) { + _env->ReleasePrimitiveArrayCritical(textures_ref, textures_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGenTextures ( GLsizei n, GLuint *textures ) */ +static void +android_glGenTextures__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject textures_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLuint *textures = (GLuint *) 0; + + textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining); + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glGenTextures( + (GLsizei)n, + (GLuint *)textures + ); + +exit: + if (_array) { + releasePointer(_env, _array, textures, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* GLenum glGetError ( void ) */ +static jint +android_glGetError__ + (JNIEnv *_env, jobject _this) { + GLenum _returnValue; + _returnValue = glGetError(); + return _returnValue; +} + +/* void glGetIntegerv ( GLenum pname, GLint *params ) */ +static void +android_glGetIntegerv__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_ALPHA_BITS) + case GL_ALPHA_BITS: +#endif // defined(GL_ALPHA_BITS) +#if defined(GL_ALPHA_TEST_FUNC) + case GL_ALPHA_TEST_FUNC: +#endif // defined(GL_ALPHA_TEST_FUNC) +#if defined(GL_ALPHA_TEST_REF) + case GL_ALPHA_TEST_REF: +#endif // defined(GL_ALPHA_TEST_REF) +#if defined(GL_BLEND_DST) + case GL_BLEND_DST: +#endif // defined(GL_BLEND_DST) +#if defined(GL_BLUE_BITS) + case GL_BLUE_BITS: +#endif // defined(GL_BLUE_BITS) +#if defined(GL_COLOR_ARRAY_BUFFER_BINDING) + case GL_COLOR_ARRAY_BUFFER_BINDING: +#endif // defined(GL_COLOR_ARRAY_BUFFER_BINDING) +#if defined(GL_COLOR_ARRAY_SIZE) + case GL_COLOR_ARRAY_SIZE: +#endif // defined(GL_COLOR_ARRAY_SIZE) +#if defined(GL_COLOR_ARRAY_STRIDE) + case GL_COLOR_ARRAY_STRIDE: +#endif // defined(GL_COLOR_ARRAY_STRIDE) +#if defined(GL_COLOR_ARRAY_TYPE) + case GL_COLOR_ARRAY_TYPE: +#endif // defined(GL_COLOR_ARRAY_TYPE) +#if defined(GL_CULL_FACE) + case GL_CULL_FACE: +#endif // defined(GL_CULL_FACE) +#if defined(GL_DEPTH_BITS) + case GL_DEPTH_BITS: +#endif // defined(GL_DEPTH_BITS) +#if defined(GL_DEPTH_CLEAR_VALUE) + case GL_DEPTH_CLEAR_VALUE: +#endif // defined(GL_DEPTH_CLEAR_VALUE) +#if defined(GL_DEPTH_FUNC) + case GL_DEPTH_FUNC: +#endif // defined(GL_DEPTH_FUNC) +#if defined(GL_DEPTH_WRITEMASK) + case GL_DEPTH_WRITEMASK: +#endif // defined(GL_DEPTH_WRITEMASK) +#if defined(GL_FOG_DENSITY) + case GL_FOG_DENSITY: +#endif // defined(GL_FOG_DENSITY) +#if defined(GL_FOG_END) + case GL_FOG_END: +#endif // defined(GL_FOG_END) +#if defined(GL_FOG_MODE) + case GL_FOG_MODE: +#endif // defined(GL_FOG_MODE) +#if defined(GL_FOG_START) + case GL_FOG_START: +#endif // defined(GL_FOG_START) +#if defined(GL_FRONT_FACE) + case GL_FRONT_FACE: +#endif // defined(GL_FRONT_FACE) +#if defined(GL_GREEN_BITS) + case GL_GREEN_BITS: +#endif // defined(GL_GREEN_BITS) +#if defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES) + case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: +#endif // defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES) +#if defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) + case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: +#endif // defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) +#if defined(GL_LIGHT_MODEL_COLOR_CONTROL) + case GL_LIGHT_MODEL_COLOR_CONTROL: +#endif // defined(GL_LIGHT_MODEL_COLOR_CONTROL) +#if defined(GL_LIGHT_MODEL_LOCAL_VIEWER) + case GL_LIGHT_MODEL_LOCAL_VIEWER: +#endif // defined(GL_LIGHT_MODEL_LOCAL_VIEWER) +#if defined(GL_LIGHT_MODEL_TWO_SIDE) + case GL_LIGHT_MODEL_TWO_SIDE: +#endif // defined(GL_LIGHT_MODEL_TWO_SIDE) +#if defined(GL_LINE_SMOOTH_HINT) + case GL_LINE_SMOOTH_HINT: +#endif // defined(GL_LINE_SMOOTH_HINT) +#if defined(GL_LINE_WIDTH) + case GL_LINE_WIDTH: +#endif // defined(GL_LINE_WIDTH) +#if defined(GL_LOGIC_OP_MODE) + case GL_LOGIC_OP_MODE: +#endif // defined(GL_LOGIC_OP_MODE) +#if defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES) + case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES) +#if defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES) + case GL_MATRIX_INDEX_ARRAY_SIZE_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES) +#if defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES) + case GL_MATRIX_INDEX_ARRAY_STRIDE_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES) +#if defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES) + case GL_MATRIX_INDEX_ARRAY_TYPE_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES) +#if defined(GL_MATRIX_MODE) + case GL_MATRIX_MODE: +#endif // defined(GL_MATRIX_MODE) +#if defined(GL_MAX_CLIP_PLANES) + case GL_MAX_CLIP_PLANES: +#endif // defined(GL_MAX_CLIP_PLANES) +#if defined(GL_MAX_ELEMENTS_INDICES) + case GL_MAX_ELEMENTS_INDICES: +#endif // defined(GL_MAX_ELEMENTS_INDICES) +#if defined(GL_MAX_ELEMENTS_VERTICES) + case GL_MAX_ELEMENTS_VERTICES: +#endif // defined(GL_MAX_ELEMENTS_VERTICES) +#if defined(GL_MAX_LIGHTS) + case GL_MAX_LIGHTS: +#endif // defined(GL_MAX_LIGHTS) +#if defined(GL_MAX_MODELVIEW_STACK_DEPTH) + case GL_MAX_MODELVIEW_STACK_DEPTH: +#endif // defined(GL_MAX_MODELVIEW_STACK_DEPTH) +#if defined(GL_MAX_PALETTE_MATRICES_OES) + case GL_MAX_PALETTE_MATRICES_OES: +#endif // defined(GL_MAX_PALETTE_MATRICES_OES) +#if defined(GL_MAX_PROJECTION_STACK_DEPTH) + case GL_MAX_PROJECTION_STACK_DEPTH: +#endif // defined(GL_MAX_PROJECTION_STACK_DEPTH) +#if defined(GL_MAX_TEXTURE_SIZE) + case GL_MAX_TEXTURE_SIZE: +#endif // defined(GL_MAX_TEXTURE_SIZE) +#if defined(GL_MAX_TEXTURE_STACK_DEPTH) + case GL_MAX_TEXTURE_STACK_DEPTH: +#endif // defined(GL_MAX_TEXTURE_STACK_DEPTH) +#if defined(GL_MAX_TEXTURE_UNITS) + case GL_MAX_TEXTURE_UNITS: +#endif // defined(GL_MAX_TEXTURE_UNITS) +#if defined(GL_MAX_VERTEX_UNITS_OES) + case GL_MAX_VERTEX_UNITS_OES: +#endif // defined(GL_MAX_VERTEX_UNITS_OES) +#if defined(GL_MODELVIEW_STACK_DEPTH) + case GL_MODELVIEW_STACK_DEPTH: +#endif // defined(GL_MODELVIEW_STACK_DEPTH) +#if defined(GL_NORMAL_ARRAY_BUFFER_BINDING) + case GL_NORMAL_ARRAY_BUFFER_BINDING: +#endif // defined(GL_NORMAL_ARRAY_BUFFER_BINDING) +#if defined(GL_NORMAL_ARRAY_STRIDE) + case GL_NORMAL_ARRAY_STRIDE: +#endif // defined(GL_NORMAL_ARRAY_STRIDE) +#if defined(GL_NORMAL_ARRAY_TYPE) + case GL_NORMAL_ARRAY_TYPE: +#endif // defined(GL_NORMAL_ARRAY_TYPE) +#if defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS) + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: +#endif // defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS) +#if defined(GL_PACK_ALIGNMENT) + case GL_PACK_ALIGNMENT: +#endif // defined(GL_PACK_ALIGNMENT) +#if defined(GL_PERSPECTIVE_CORRECTION_HINT) + case GL_PERSPECTIVE_CORRECTION_HINT: +#endif // defined(GL_PERSPECTIVE_CORRECTION_HINT) +#if defined(GL_POINT_SIZE) + case GL_POINT_SIZE: +#endif // defined(GL_POINT_SIZE) +#if defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES) + case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: +#endif // defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES) +#if defined(GL_POINT_SIZE_ARRAY_STRIDE_OES) + case GL_POINT_SIZE_ARRAY_STRIDE_OES: +#endif // defined(GL_POINT_SIZE_ARRAY_STRIDE_OES) +#if defined(GL_POINT_SIZE_ARRAY_TYPE_OES) + case GL_POINT_SIZE_ARRAY_TYPE_OES: +#endif // defined(GL_POINT_SIZE_ARRAY_TYPE_OES) +#if defined(GL_POINT_SMOOTH_HINT) + case GL_POINT_SMOOTH_HINT: +#endif // defined(GL_POINT_SMOOTH_HINT) +#if defined(GL_POLYGON_OFFSET_FACTOR) + case GL_POLYGON_OFFSET_FACTOR: +#endif // defined(GL_POLYGON_OFFSET_FACTOR) +#if defined(GL_POLYGON_OFFSET_UNITS) + case GL_POLYGON_OFFSET_UNITS: +#endif // defined(GL_POLYGON_OFFSET_UNITS) +#if defined(GL_PROJECTION_STACK_DEPTH) + case GL_PROJECTION_STACK_DEPTH: +#endif // defined(GL_PROJECTION_STACK_DEPTH) +#if defined(GL_RED_BITS) + case GL_RED_BITS: +#endif // defined(GL_RED_BITS) +#if defined(GL_SHADE_MODEL) + case GL_SHADE_MODEL: +#endif // defined(GL_SHADE_MODEL) +#if defined(GL_STENCIL_BITS) + case GL_STENCIL_BITS: +#endif // defined(GL_STENCIL_BITS) +#if defined(GL_STENCIL_CLEAR_VALUE) + case GL_STENCIL_CLEAR_VALUE: +#endif // defined(GL_STENCIL_CLEAR_VALUE) +#if defined(GL_STENCIL_FAIL) + case GL_STENCIL_FAIL: +#endif // defined(GL_STENCIL_FAIL) +#if defined(GL_STENCIL_FUNC) + case GL_STENCIL_FUNC: +#endif // defined(GL_STENCIL_FUNC) +#if defined(GL_STENCIL_PASS_DEPTH_FAIL) + case GL_STENCIL_PASS_DEPTH_FAIL: +#endif // defined(GL_STENCIL_PASS_DEPTH_FAIL) +#if defined(GL_STENCIL_PASS_DEPTH_PASS) + case GL_STENCIL_PASS_DEPTH_PASS: +#endif // defined(GL_STENCIL_PASS_DEPTH_PASS) +#if defined(GL_STENCIL_REF) + case GL_STENCIL_REF: +#endif // defined(GL_STENCIL_REF) +#if defined(GL_STENCIL_VALUE_MASK) + case GL_STENCIL_VALUE_MASK: +#endif // defined(GL_STENCIL_VALUE_MASK) +#if defined(GL_STENCIL_WRITEMASK) + case GL_STENCIL_WRITEMASK: +#endif // defined(GL_STENCIL_WRITEMASK) +#if defined(GL_SUBPIXEL_BITS) + case GL_SUBPIXEL_BITS: +#endif // defined(GL_SUBPIXEL_BITS) +#if defined(GL_TEXTURE_BINDING_2D) + case GL_TEXTURE_BINDING_2D: +#endif // defined(GL_TEXTURE_BINDING_2D) +#if defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING) + case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: +#endif // defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING) +#if defined(GL_TEXTURE_COORD_ARRAY_SIZE) + case GL_TEXTURE_COORD_ARRAY_SIZE: +#endif // defined(GL_TEXTURE_COORD_ARRAY_SIZE) +#if defined(GL_TEXTURE_COORD_ARRAY_STRIDE) + case GL_TEXTURE_COORD_ARRAY_STRIDE: +#endif // defined(GL_TEXTURE_COORD_ARRAY_STRIDE) +#if defined(GL_TEXTURE_COORD_ARRAY_TYPE) + case GL_TEXTURE_COORD_ARRAY_TYPE: +#endif // defined(GL_TEXTURE_COORD_ARRAY_TYPE) +#if defined(GL_TEXTURE_STACK_DEPTH) + case GL_TEXTURE_STACK_DEPTH: +#endif // defined(GL_TEXTURE_STACK_DEPTH) +#if defined(GL_UNPACK_ALIGNMENT) + case GL_UNPACK_ALIGNMENT: +#endif // defined(GL_UNPACK_ALIGNMENT) +#if defined(GL_VERTEX_ARRAY_BUFFER_BINDING) + case GL_VERTEX_ARRAY_BUFFER_BINDING: +#endif // defined(GL_VERTEX_ARRAY_BUFFER_BINDING) +#if defined(GL_VERTEX_ARRAY_SIZE) + case GL_VERTEX_ARRAY_SIZE: +#endif // defined(GL_VERTEX_ARRAY_SIZE) +#if defined(GL_VERTEX_ARRAY_STRIDE) + case GL_VERTEX_ARRAY_STRIDE: +#endif // defined(GL_VERTEX_ARRAY_STRIDE) +#if defined(GL_VERTEX_ARRAY_TYPE) + case GL_VERTEX_ARRAY_TYPE: +#endif // defined(GL_VERTEX_ARRAY_TYPE) +#if defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES) + case GL_WEIGHT_ARRAY_BUFFER_BINDING_OES: +#endif // defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES) +#if defined(GL_WEIGHT_ARRAY_SIZE_OES) + case GL_WEIGHT_ARRAY_SIZE_OES: +#endif // defined(GL_WEIGHT_ARRAY_SIZE_OES) +#if defined(GL_WEIGHT_ARRAY_STRIDE_OES) + case GL_WEIGHT_ARRAY_STRIDE_OES: +#endif // defined(GL_WEIGHT_ARRAY_STRIDE_OES) +#if defined(GL_WEIGHT_ARRAY_TYPE_OES) + case GL_WEIGHT_ARRAY_TYPE_OES: +#endif // defined(GL_WEIGHT_ARRAY_TYPE_OES) + _needed = 1; + break; +#if defined(GL_ALIASED_POINT_SIZE_RANGE) + case GL_ALIASED_POINT_SIZE_RANGE: +#endif // defined(GL_ALIASED_POINT_SIZE_RANGE) +#if defined(GL_ALIASED_LINE_WIDTH_RANGE) + case GL_ALIASED_LINE_WIDTH_RANGE: +#endif // defined(GL_ALIASED_LINE_WIDTH_RANGE) +#if defined(GL_DEPTH_RANGE) + case GL_DEPTH_RANGE: +#endif // defined(GL_DEPTH_RANGE) +#if defined(GL_MAX_VIEWPORT_DIMS) + case GL_MAX_VIEWPORT_DIMS: +#endif // defined(GL_MAX_VIEWPORT_DIMS) +#if defined(GL_SMOOTH_LINE_WIDTH_RANGE) + case GL_SMOOTH_LINE_WIDTH_RANGE: +#endif // defined(GL_SMOOTH_LINE_WIDTH_RANGE) +#if defined(GL_SMOOTH_POINT_SIZE_RANGE) + case GL_SMOOTH_POINT_SIZE_RANGE: +#endif // defined(GL_SMOOTH_POINT_SIZE_RANGE) + _needed = 2; + break; +#if defined(GL_COLOR_CLEAR_VALUE) + case GL_COLOR_CLEAR_VALUE: +#endif // defined(GL_COLOR_CLEAR_VALUE) +#if defined(GL_COLOR_WRITEMASK) + case GL_COLOR_WRITEMASK: +#endif // defined(GL_COLOR_WRITEMASK) +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) +#if defined(GL_SCISSOR_BOX) + case GL_SCISSOR_BOX: +#endif // defined(GL_SCISSOR_BOX) +#if defined(GL_VIEWPORT) + case GL_VIEWPORT: +#endif // defined(GL_VIEWPORT) + _needed = 4; + break; +#if defined(GL_MODELVIEW_MATRIX) + case GL_MODELVIEW_MATRIX: +#endif // defined(GL_MODELVIEW_MATRIX) +#if defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES) + case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES: +#endif // defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES) +#if defined(GL_PROJECTION_MATRIX) + case GL_PROJECTION_MATRIX: +#endif // defined(GL_PROJECTION_MATRIX) +#if defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES) + case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES: +#endif // defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES) +#if defined(GL_TEXTURE_MATRIX) + case GL_TEXTURE_MATRIX: +#endif // defined(GL_TEXTURE_MATRIX) +#if defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES) + case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES: +#endif // defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES) + _needed = 16; + break; +#if defined(GL_COMPRESSED_TEXTURE_FORMATS) + case GL_COMPRESSED_TEXTURE_FORMATS: +#endif // defined(GL_COMPRESSED_TEXTURE_FORMATS) + _needed = getNumCompressedTextureFormats(); + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetIntegerv( + (GLenum)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetIntegerv ( GLenum pname, GLint *params ) */ +static void +android_glGetIntegerv__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_ALPHA_BITS) + case GL_ALPHA_BITS: +#endif // defined(GL_ALPHA_BITS) +#if defined(GL_ALPHA_TEST_FUNC) + case GL_ALPHA_TEST_FUNC: +#endif // defined(GL_ALPHA_TEST_FUNC) +#if defined(GL_ALPHA_TEST_REF) + case GL_ALPHA_TEST_REF: +#endif // defined(GL_ALPHA_TEST_REF) +#if defined(GL_BLEND_DST) + case GL_BLEND_DST: +#endif // defined(GL_BLEND_DST) +#if defined(GL_BLUE_BITS) + case GL_BLUE_BITS: +#endif // defined(GL_BLUE_BITS) +#if defined(GL_COLOR_ARRAY_BUFFER_BINDING) + case GL_COLOR_ARRAY_BUFFER_BINDING: +#endif // defined(GL_COLOR_ARRAY_BUFFER_BINDING) +#if defined(GL_COLOR_ARRAY_SIZE) + case GL_COLOR_ARRAY_SIZE: +#endif // defined(GL_COLOR_ARRAY_SIZE) +#if defined(GL_COLOR_ARRAY_STRIDE) + case GL_COLOR_ARRAY_STRIDE: +#endif // defined(GL_COLOR_ARRAY_STRIDE) +#if defined(GL_COLOR_ARRAY_TYPE) + case GL_COLOR_ARRAY_TYPE: +#endif // defined(GL_COLOR_ARRAY_TYPE) +#if defined(GL_CULL_FACE) + case GL_CULL_FACE: +#endif // defined(GL_CULL_FACE) +#if defined(GL_DEPTH_BITS) + case GL_DEPTH_BITS: +#endif // defined(GL_DEPTH_BITS) +#if defined(GL_DEPTH_CLEAR_VALUE) + case GL_DEPTH_CLEAR_VALUE: +#endif // defined(GL_DEPTH_CLEAR_VALUE) +#if defined(GL_DEPTH_FUNC) + case GL_DEPTH_FUNC: +#endif // defined(GL_DEPTH_FUNC) +#if defined(GL_DEPTH_WRITEMASK) + case GL_DEPTH_WRITEMASK: +#endif // defined(GL_DEPTH_WRITEMASK) +#if defined(GL_FOG_DENSITY) + case GL_FOG_DENSITY: +#endif // defined(GL_FOG_DENSITY) +#if defined(GL_FOG_END) + case GL_FOG_END: +#endif // defined(GL_FOG_END) +#if defined(GL_FOG_MODE) + case GL_FOG_MODE: +#endif // defined(GL_FOG_MODE) +#if defined(GL_FOG_START) + case GL_FOG_START: +#endif // defined(GL_FOG_START) +#if defined(GL_FRONT_FACE) + case GL_FRONT_FACE: +#endif // defined(GL_FRONT_FACE) +#if defined(GL_GREEN_BITS) + case GL_GREEN_BITS: +#endif // defined(GL_GREEN_BITS) +#if defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES) + case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: +#endif // defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES) +#if defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) + case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: +#endif // defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) +#if defined(GL_LIGHT_MODEL_COLOR_CONTROL) + case GL_LIGHT_MODEL_COLOR_CONTROL: +#endif // defined(GL_LIGHT_MODEL_COLOR_CONTROL) +#if defined(GL_LIGHT_MODEL_LOCAL_VIEWER) + case GL_LIGHT_MODEL_LOCAL_VIEWER: +#endif // defined(GL_LIGHT_MODEL_LOCAL_VIEWER) +#if defined(GL_LIGHT_MODEL_TWO_SIDE) + case GL_LIGHT_MODEL_TWO_SIDE: +#endif // defined(GL_LIGHT_MODEL_TWO_SIDE) +#if defined(GL_LINE_SMOOTH_HINT) + case GL_LINE_SMOOTH_HINT: +#endif // defined(GL_LINE_SMOOTH_HINT) +#if defined(GL_LINE_WIDTH) + case GL_LINE_WIDTH: +#endif // defined(GL_LINE_WIDTH) +#if defined(GL_LOGIC_OP_MODE) + case GL_LOGIC_OP_MODE: +#endif // defined(GL_LOGIC_OP_MODE) +#if defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES) + case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES) +#if defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES) + case GL_MATRIX_INDEX_ARRAY_SIZE_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES) +#if defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES) + case GL_MATRIX_INDEX_ARRAY_STRIDE_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES) +#if defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES) + case GL_MATRIX_INDEX_ARRAY_TYPE_OES: +#endif // defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES) +#if defined(GL_MATRIX_MODE) + case GL_MATRIX_MODE: +#endif // defined(GL_MATRIX_MODE) +#if defined(GL_MAX_CLIP_PLANES) + case GL_MAX_CLIP_PLANES: +#endif // defined(GL_MAX_CLIP_PLANES) +#if defined(GL_MAX_ELEMENTS_INDICES) + case GL_MAX_ELEMENTS_INDICES: +#endif // defined(GL_MAX_ELEMENTS_INDICES) +#if defined(GL_MAX_ELEMENTS_VERTICES) + case GL_MAX_ELEMENTS_VERTICES: +#endif // defined(GL_MAX_ELEMENTS_VERTICES) +#if defined(GL_MAX_LIGHTS) + case GL_MAX_LIGHTS: +#endif // defined(GL_MAX_LIGHTS) +#if defined(GL_MAX_MODELVIEW_STACK_DEPTH) + case GL_MAX_MODELVIEW_STACK_DEPTH: +#endif // defined(GL_MAX_MODELVIEW_STACK_DEPTH) +#if defined(GL_MAX_PALETTE_MATRICES_OES) + case GL_MAX_PALETTE_MATRICES_OES: +#endif // defined(GL_MAX_PALETTE_MATRICES_OES) +#if defined(GL_MAX_PROJECTION_STACK_DEPTH) + case GL_MAX_PROJECTION_STACK_DEPTH: +#endif // defined(GL_MAX_PROJECTION_STACK_DEPTH) +#if defined(GL_MAX_TEXTURE_SIZE) + case GL_MAX_TEXTURE_SIZE: +#endif // defined(GL_MAX_TEXTURE_SIZE) +#if defined(GL_MAX_TEXTURE_STACK_DEPTH) + case GL_MAX_TEXTURE_STACK_DEPTH: +#endif // defined(GL_MAX_TEXTURE_STACK_DEPTH) +#if defined(GL_MAX_TEXTURE_UNITS) + case GL_MAX_TEXTURE_UNITS: +#endif // defined(GL_MAX_TEXTURE_UNITS) +#if defined(GL_MAX_VERTEX_UNITS_OES) + case GL_MAX_VERTEX_UNITS_OES: +#endif // defined(GL_MAX_VERTEX_UNITS_OES) +#if defined(GL_MODELVIEW_STACK_DEPTH) + case GL_MODELVIEW_STACK_DEPTH: +#endif // defined(GL_MODELVIEW_STACK_DEPTH) +#if defined(GL_NORMAL_ARRAY_BUFFER_BINDING) + case GL_NORMAL_ARRAY_BUFFER_BINDING: +#endif // defined(GL_NORMAL_ARRAY_BUFFER_BINDING) +#if defined(GL_NORMAL_ARRAY_STRIDE) + case GL_NORMAL_ARRAY_STRIDE: +#endif // defined(GL_NORMAL_ARRAY_STRIDE) +#if defined(GL_NORMAL_ARRAY_TYPE) + case GL_NORMAL_ARRAY_TYPE: +#endif // defined(GL_NORMAL_ARRAY_TYPE) +#if defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS) + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: +#endif // defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS) +#if defined(GL_PACK_ALIGNMENT) + case GL_PACK_ALIGNMENT: +#endif // defined(GL_PACK_ALIGNMENT) +#if defined(GL_PERSPECTIVE_CORRECTION_HINT) + case GL_PERSPECTIVE_CORRECTION_HINT: +#endif // defined(GL_PERSPECTIVE_CORRECTION_HINT) +#if defined(GL_POINT_SIZE) + case GL_POINT_SIZE: +#endif // defined(GL_POINT_SIZE) +#if defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES) + case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: +#endif // defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES) +#if defined(GL_POINT_SIZE_ARRAY_STRIDE_OES) + case GL_POINT_SIZE_ARRAY_STRIDE_OES: +#endif // defined(GL_POINT_SIZE_ARRAY_STRIDE_OES) +#if defined(GL_POINT_SIZE_ARRAY_TYPE_OES) + case GL_POINT_SIZE_ARRAY_TYPE_OES: +#endif // defined(GL_POINT_SIZE_ARRAY_TYPE_OES) +#if defined(GL_POINT_SMOOTH_HINT) + case GL_POINT_SMOOTH_HINT: +#endif // defined(GL_POINT_SMOOTH_HINT) +#if defined(GL_POLYGON_OFFSET_FACTOR) + case GL_POLYGON_OFFSET_FACTOR: +#endif // defined(GL_POLYGON_OFFSET_FACTOR) +#if defined(GL_POLYGON_OFFSET_UNITS) + case GL_POLYGON_OFFSET_UNITS: +#endif // defined(GL_POLYGON_OFFSET_UNITS) +#if defined(GL_PROJECTION_STACK_DEPTH) + case GL_PROJECTION_STACK_DEPTH: +#endif // defined(GL_PROJECTION_STACK_DEPTH) +#if defined(GL_RED_BITS) + case GL_RED_BITS: +#endif // defined(GL_RED_BITS) +#if defined(GL_SHADE_MODEL) + case GL_SHADE_MODEL: +#endif // defined(GL_SHADE_MODEL) +#if defined(GL_STENCIL_BITS) + case GL_STENCIL_BITS: +#endif // defined(GL_STENCIL_BITS) +#if defined(GL_STENCIL_CLEAR_VALUE) + case GL_STENCIL_CLEAR_VALUE: +#endif // defined(GL_STENCIL_CLEAR_VALUE) +#if defined(GL_STENCIL_FAIL) + case GL_STENCIL_FAIL: +#endif // defined(GL_STENCIL_FAIL) +#if defined(GL_STENCIL_FUNC) + case GL_STENCIL_FUNC: +#endif // defined(GL_STENCIL_FUNC) +#if defined(GL_STENCIL_PASS_DEPTH_FAIL) + case GL_STENCIL_PASS_DEPTH_FAIL: +#endif // defined(GL_STENCIL_PASS_DEPTH_FAIL) +#if defined(GL_STENCIL_PASS_DEPTH_PASS) + case GL_STENCIL_PASS_DEPTH_PASS: +#endif // defined(GL_STENCIL_PASS_DEPTH_PASS) +#if defined(GL_STENCIL_REF) + case GL_STENCIL_REF: +#endif // defined(GL_STENCIL_REF) +#if defined(GL_STENCIL_VALUE_MASK) + case GL_STENCIL_VALUE_MASK: +#endif // defined(GL_STENCIL_VALUE_MASK) +#if defined(GL_STENCIL_WRITEMASK) + case GL_STENCIL_WRITEMASK: +#endif // defined(GL_STENCIL_WRITEMASK) +#if defined(GL_SUBPIXEL_BITS) + case GL_SUBPIXEL_BITS: +#endif // defined(GL_SUBPIXEL_BITS) +#if defined(GL_TEXTURE_BINDING_2D) + case GL_TEXTURE_BINDING_2D: +#endif // defined(GL_TEXTURE_BINDING_2D) +#if defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING) + case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: +#endif // defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING) +#if defined(GL_TEXTURE_COORD_ARRAY_SIZE) + case GL_TEXTURE_COORD_ARRAY_SIZE: +#endif // defined(GL_TEXTURE_COORD_ARRAY_SIZE) +#if defined(GL_TEXTURE_COORD_ARRAY_STRIDE) + case GL_TEXTURE_COORD_ARRAY_STRIDE: +#endif // defined(GL_TEXTURE_COORD_ARRAY_STRIDE) +#if defined(GL_TEXTURE_COORD_ARRAY_TYPE) + case GL_TEXTURE_COORD_ARRAY_TYPE: +#endif // defined(GL_TEXTURE_COORD_ARRAY_TYPE) +#if defined(GL_TEXTURE_STACK_DEPTH) + case GL_TEXTURE_STACK_DEPTH: +#endif // defined(GL_TEXTURE_STACK_DEPTH) +#if defined(GL_UNPACK_ALIGNMENT) + case GL_UNPACK_ALIGNMENT: +#endif // defined(GL_UNPACK_ALIGNMENT) +#if defined(GL_VERTEX_ARRAY_BUFFER_BINDING) + case GL_VERTEX_ARRAY_BUFFER_BINDING: +#endif // defined(GL_VERTEX_ARRAY_BUFFER_BINDING) +#if defined(GL_VERTEX_ARRAY_SIZE) + case GL_VERTEX_ARRAY_SIZE: +#endif // defined(GL_VERTEX_ARRAY_SIZE) +#if defined(GL_VERTEX_ARRAY_STRIDE) + case GL_VERTEX_ARRAY_STRIDE: +#endif // defined(GL_VERTEX_ARRAY_STRIDE) +#if defined(GL_VERTEX_ARRAY_TYPE) + case GL_VERTEX_ARRAY_TYPE: +#endif // defined(GL_VERTEX_ARRAY_TYPE) +#if defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES) + case GL_WEIGHT_ARRAY_BUFFER_BINDING_OES: +#endif // defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES) +#if defined(GL_WEIGHT_ARRAY_SIZE_OES) + case GL_WEIGHT_ARRAY_SIZE_OES: +#endif // defined(GL_WEIGHT_ARRAY_SIZE_OES) +#if defined(GL_WEIGHT_ARRAY_STRIDE_OES) + case GL_WEIGHT_ARRAY_STRIDE_OES: +#endif // defined(GL_WEIGHT_ARRAY_STRIDE_OES) +#if defined(GL_WEIGHT_ARRAY_TYPE_OES) + case GL_WEIGHT_ARRAY_TYPE_OES: +#endif // defined(GL_WEIGHT_ARRAY_TYPE_OES) + _needed = 1; + break; +#if defined(GL_ALIASED_POINT_SIZE_RANGE) + case GL_ALIASED_POINT_SIZE_RANGE: +#endif // defined(GL_ALIASED_POINT_SIZE_RANGE) +#if defined(GL_ALIASED_LINE_WIDTH_RANGE) + case GL_ALIASED_LINE_WIDTH_RANGE: +#endif // defined(GL_ALIASED_LINE_WIDTH_RANGE) +#if defined(GL_DEPTH_RANGE) + case GL_DEPTH_RANGE: +#endif // defined(GL_DEPTH_RANGE) +#if defined(GL_MAX_VIEWPORT_DIMS) + case GL_MAX_VIEWPORT_DIMS: +#endif // defined(GL_MAX_VIEWPORT_DIMS) +#if defined(GL_SMOOTH_LINE_WIDTH_RANGE) + case GL_SMOOTH_LINE_WIDTH_RANGE: +#endif // defined(GL_SMOOTH_LINE_WIDTH_RANGE) +#if defined(GL_SMOOTH_POINT_SIZE_RANGE) + case GL_SMOOTH_POINT_SIZE_RANGE: +#endif // defined(GL_SMOOTH_POINT_SIZE_RANGE) + _needed = 2; + break; +#if defined(GL_COLOR_CLEAR_VALUE) + case GL_COLOR_CLEAR_VALUE: +#endif // defined(GL_COLOR_CLEAR_VALUE) +#if defined(GL_COLOR_WRITEMASK) + case GL_COLOR_WRITEMASK: +#endif // defined(GL_COLOR_WRITEMASK) +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) +#if defined(GL_SCISSOR_BOX) + case GL_SCISSOR_BOX: +#endif // defined(GL_SCISSOR_BOX) +#if defined(GL_VIEWPORT) + case GL_VIEWPORT: +#endif // defined(GL_VIEWPORT) + _needed = 4; + break; +#if defined(GL_MODELVIEW_MATRIX) + case GL_MODELVIEW_MATRIX: +#endif // defined(GL_MODELVIEW_MATRIX) +#if defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES) + case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES: +#endif // defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES) +#if defined(GL_PROJECTION_MATRIX) + case GL_PROJECTION_MATRIX: +#endif // defined(GL_PROJECTION_MATRIX) +#if defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES) + case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES: +#endif // defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES) +#if defined(GL_TEXTURE_MATRIX) + case GL_TEXTURE_MATRIX: +#endif // defined(GL_TEXTURE_MATRIX) +#if defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES) + case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES: +#endif // defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES) + _needed = 16; + break; +#if defined(GL_COMPRESSED_TEXTURE_FORMATS) + case GL_COMPRESSED_TEXTURE_FORMATS: +#endif // defined(GL_COMPRESSED_TEXTURE_FORMATS) + _needed = getNumCompressedTextureFormats(); + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetIntegerv( + (GLenum)pname, + (GLint *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +#include + +/* const GLubyte * glGetString ( GLenum name ) */ +static +jstring +android_glGetString + (JNIEnv *_env, jobject _this, jint name) { + const char * chars = (const char *)glGetString((GLenum)name); + jstring output = _env->NewStringUTF(chars); + return output; +} +/* void glHint ( GLenum target, GLenum mode ) */ +static void +android_glHint__II + (JNIEnv *_env, jobject _this, jint target, jint mode) { + glHint( + (GLenum)target, + (GLenum)mode + ); +} + +/* void glLightModelf ( GLenum pname, GLfloat param ) */ +static void +android_glLightModelf__IF + (JNIEnv *_env, jobject _this, jint pname, jfloat param) { + glLightModelf( + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glLightModelfv ( GLenum pname, const GLfloat *params ) */ +static void +android_glLightModelfv__I_3FI + (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_LIGHT_MODEL_TWO_SIDE) + case GL_LIGHT_MODEL_TWO_SIDE: +#endif // defined(GL_LIGHT_MODEL_TWO_SIDE) + _needed = 1; + break; +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glLightModelfv( + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glLightModelfv ( GLenum pname, const GLfloat *params ) */ +static void +android_glLightModelfv__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_LIGHT_MODEL_TWO_SIDE) + case GL_LIGHT_MODEL_TWO_SIDE: +#endif // defined(GL_LIGHT_MODEL_TWO_SIDE) + _needed = 1; + break; +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glLightModelfv( + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glLightModelx ( GLenum pname, GLfixed param ) */ +static void +android_glLightModelx__II + (JNIEnv *_env, jobject _this, jint pname, jint param) { + glLightModelx( + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glLightModelxv ( GLenum pname, const GLfixed *params ) */ +static void +android_glLightModelxv__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_LIGHT_MODEL_TWO_SIDE) + case GL_LIGHT_MODEL_TWO_SIDE: +#endif // defined(GL_LIGHT_MODEL_TWO_SIDE) + _needed = 1; + break; +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glLightModelxv( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glLightModelxv ( GLenum pname, const GLfixed *params ) */ +static void +android_glLightModelxv__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_LIGHT_MODEL_TWO_SIDE) + case GL_LIGHT_MODEL_TWO_SIDE: +#endif // defined(GL_LIGHT_MODEL_TWO_SIDE) + _needed = 1; + break; +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glLightModelxv( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glLightf ( GLenum light, GLenum pname, GLfloat param ) */ +static void +android_glLightf__IIF + (JNIEnv *_env, jobject _this, jint light, jint pname, jfloat param) { + glLightf( + (GLenum)light, + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) */ +static void +android_glLightfv__II_3FI + (JNIEnv *_env, jobject _this, jint light, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glLightfv( + (GLenum)light, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) */ +static void +android_glLightfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glLightfv( + (GLenum)light, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glLightx ( GLenum light, GLenum pname, GLfixed param ) */ +static void +android_glLightx__III + (JNIEnv *_env, jobject _this, jint light, jint pname, jint param) { + glLightx( + (GLenum)light, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) */ +static void +android_glLightxv__II_3II + (JNIEnv *_env, jobject _this, jint light, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glLightxv( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) */ +static void +android_glLightxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glLightxv( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glLineWidth ( GLfloat width ) */ +static void +android_glLineWidth__F + (JNIEnv *_env, jobject _this, jfloat width) { + glLineWidth( + (GLfloat)width + ); +} + +/* void glLineWidthx ( GLfixed width ) */ +static void +android_glLineWidthx__I + (JNIEnv *_env, jobject _this, jint width) { + glLineWidthx( + (GLfixed)width + ); +} + +/* void glLoadIdentity ( void ) */ +static void +android_glLoadIdentity__ + (JNIEnv *_env, jobject _this) { + glLoadIdentity(); +} + +/* void glLoadMatrixf ( const GLfloat *m ) */ +static void +android_glLoadMatrixf___3FI + (JNIEnv *_env, jobject _this, jfloatArray m_ref, jint offset) { + GLfloat *m_base = (GLfloat *) 0; + jint _remaining; + GLfloat *m = (GLfloat *) 0; + + if (!m_ref) { + _env->ThrowNew(IAEClass, "m == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(m_ref) - offset; + m_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0); + m = m_base + offset; + + glLoadMatrixf( + (GLfloat *)m + ); + +exit: + if (m_base) { + _env->ReleasePrimitiveArrayCritical(m_ref, m_base, + JNI_ABORT); + } +} + +/* void glLoadMatrixf ( const GLfloat *m ) */ +static void +android_glLoadMatrixf__Ljava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jobject m_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *m = (GLfloat *) 0; + + m = (GLfloat *)getPointer(_env, m_buf, &_array, &_remaining); + glLoadMatrixf( + (GLfloat *)m + ); + if (_array) { + releasePointer(_env, _array, m, JNI_FALSE); + } +} + +/* void glLoadMatrixx ( const GLfixed *m ) */ +static void +android_glLoadMatrixx___3II + (JNIEnv *_env, jobject _this, jintArray m_ref, jint offset) { + GLfixed *m_base = (GLfixed *) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + if (!m_ref) { + _env->ThrowNew(IAEClass, "m == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(m_ref) - offset; + m_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0); + m = m_base + offset; + + glLoadMatrixx( + (GLfixed *)m + ); + +exit: + if (m_base) { + _env->ReleasePrimitiveArrayCritical(m_ref, m_base, + JNI_ABORT); + } +} + +/* void glLoadMatrixx ( const GLfixed *m ) */ +static void +android_glLoadMatrixx__Ljava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jobject m_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + m = (GLfixed *)getPointer(_env, m_buf, &_array, &_remaining); + glLoadMatrixx( + (GLfixed *)m + ); + if (_array) { + releasePointer(_env, _array, m, JNI_FALSE); + } +} + +/* void glLogicOp ( GLenum opcode ) */ +static void +android_glLogicOp__I + (JNIEnv *_env, jobject _this, jint opcode) { + glLogicOp( + (GLenum)opcode + ); +} + +/* void glMaterialf ( GLenum face, GLenum pname, GLfloat param ) */ +static void +android_glMaterialf__IIF + (JNIEnv *_env, jobject _this, jint face, jint pname, jfloat param) { + glMaterialf( + (GLenum)face, + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) */ +static void +android_glMaterialfv__II_3FI + (JNIEnv *_env, jobject _this, jint face, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glMaterialfv( + (GLenum)face, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) */ +static void +android_glMaterialfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glMaterialfv( + (GLenum)face, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glMaterialx ( GLenum face, GLenum pname, GLfixed param ) */ +static void +android_glMaterialx__III + (JNIEnv *_env, jobject _this, jint face, jint pname, jint param) { + glMaterialx( + (GLenum)face, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) */ +static void +android_glMaterialxv__II_3II + (JNIEnv *_env, jobject _this, jint face, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glMaterialxv( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) */ +static void +android_glMaterialxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glMaterialxv( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glMatrixMode ( GLenum mode ) */ +static void +android_glMatrixMode__I + (JNIEnv *_env, jobject _this, jint mode) { + glMatrixMode( + (GLenum)mode + ); +} + +/* void glMultMatrixf ( const GLfloat *m ) */ +static void +android_glMultMatrixf___3FI + (JNIEnv *_env, jobject _this, jfloatArray m_ref, jint offset) { + GLfloat *m_base = (GLfloat *) 0; + jint _remaining; + GLfloat *m = (GLfloat *) 0; + + if (!m_ref) { + _env->ThrowNew(IAEClass, "m == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(m_ref) - offset; + m_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0); + m = m_base + offset; + + glMultMatrixf( + (GLfloat *)m + ); + +exit: + if (m_base) { + _env->ReleasePrimitiveArrayCritical(m_ref, m_base, + JNI_ABORT); + } +} + +/* void glMultMatrixf ( const GLfloat *m ) */ +static void +android_glMultMatrixf__Ljava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jobject m_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *m = (GLfloat *) 0; + + m = (GLfloat *)getPointer(_env, m_buf, &_array, &_remaining); + glMultMatrixf( + (GLfloat *)m + ); + if (_array) { + releasePointer(_env, _array, m, JNI_FALSE); + } +} + +/* void glMultMatrixx ( const GLfixed *m ) */ +static void +android_glMultMatrixx___3II + (JNIEnv *_env, jobject _this, jintArray m_ref, jint offset) { + GLfixed *m_base = (GLfixed *) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + if (!m_ref) { + _env->ThrowNew(IAEClass, "m == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(m_ref) - offset; + m_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0); + m = m_base + offset; + + glMultMatrixx( + (GLfixed *)m + ); + +exit: + if (m_base) { + _env->ReleasePrimitiveArrayCritical(m_ref, m_base, + JNI_ABORT); + } +} + +/* void glMultMatrixx ( const GLfixed *m ) */ +static void +android_glMultMatrixx__Ljava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jobject m_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + m = (GLfixed *)getPointer(_env, m_buf, &_array, &_remaining); + glMultMatrixx( + (GLfixed *)m + ); + if (_array) { + releasePointer(_env, _array, m, JNI_FALSE); + } +} + +/* void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) */ +static void +android_glMultiTexCoord4f__IFFFF + (JNIEnv *_env, jobject _this, jint target, jfloat s, jfloat t, jfloat r, jfloat q) { + glMultiTexCoord4f( + (GLenum)target, + (GLfloat)s, + (GLfloat)t, + (GLfloat)r, + (GLfloat)q + ); +} + +/* void glMultiTexCoord4x ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) */ +static void +android_glMultiTexCoord4x__IIIII + (JNIEnv *_env, jobject _this, jint target, jint s, jint t, jint r, jint q) { + glMultiTexCoord4x( + (GLenum)target, + (GLfixed)s, + (GLfixed)t, + (GLfixed)r, + (GLfixed)q + ); +} + +/* void glNormal3f ( GLfloat nx, GLfloat ny, GLfloat nz ) */ +static void +android_glNormal3f__FFF + (JNIEnv *_env, jobject _this, jfloat nx, jfloat ny, jfloat nz) { + glNormal3f( + (GLfloat)nx, + (GLfloat)ny, + (GLfloat)nz + ); +} + +/* void glNormal3x ( GLfixed nx, GLfixed ny, GLfixed nz ) */ +static void +android_glNormal3x__III + (JNIEnv *_env, jobject _this, jint nx, jint ny, jint nz) { + glNormal3x( + (GLfixed)nx, + (GLfixed)ny, + (GLfixed)nz + ); +} + +/* void glNormalPointer ( GLenum type, GLsizei stride, const GLvoid *pointer ) */ +static void +android_glNormalPointerBounds__IILjava_nio_Buffer_2I + (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf, jint remaining) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pointer = (GLvoid *) 0; + + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } + glNormalPointerBounds( + (GLenum)type, + (GLsizei)stride, + (GLvoid *)pointer, + (GLsizei)remaining + ); +} + +/* void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */ +static void +android_glOrthof__FFFFFF + (JNIEnv *_env, jobject _this, jfloat left, jfloat right, jfloat bottom, jfloat top, jfloat zNear, jfloat zFar) { + 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 ) */ +static void +android_glOrthox__IIIIII + (JNIEnv *_env, jobject _this, jint left, jint right, jint bottom, jint top, jint zNear, jint zFar) { + glOrthox( + (GLfixed)left, + (GLfixed)right, + (GLfixed)bottom, + (GLfixed)top, + (GLfixed)zNear, + (GLfixed)zFar + ); +} + +/* void glPixelStorei ( GLenum pname, GLint param ) */ +static void +android_glPixelStorei__II + (JNIEnv *_env, jobject _this, jint pname, jint param) { + glPixelStorei( + (GLenum)pname, + (GLint)param + ); +} + +/* void glPointSize ( GLfloat size ) */ +static void +android_glPointSize__F + (JNIEnv *_env, jobject _this, jfloat size) { + glPointSize( + (GLfloat)size + ); +} + +/* void glPointSizex ( GLfixed size ) */ +static void +android_glPointSizex__I + (JNIEnv *_env, jobject _this, jint size) { + glPointSizex( + (GLfixed)size + ); +} + +/* void glPolygonOffset ( GLfloat factor, GLfloat units ) */ +static void +android_glPolygonOffset__FF + (JNIEnv *_env, jobject _this, jfloat factor, jfloat units) { + glPolygonOffset( + (GLfloat)factor, + (GLfloat)units + ); +} + +/* void glPolygonOffsetx ( GLfixed factor, GLfixed units ) */ +static void +android_glPolygonOffsetx__II + (JNIEnv *_env, jobject _this, jint factor, jint units) { + glPolygonOffsetx( + (GLfixed)factor, + (GLfixed)units + ); +} + +/* void glPopMatrix ( void ) */ +static void +android_glPopMatrix__ + (JNIEnv *_env, jobject _this) { + glPopMatrix(); +} + +/* void glPushMatrix ( void ) */ +static void +android_glPushMatrix__ + (JNIEnv *_env, jobject _this) { + glPushMatrix(); +} + +/* void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) */ +static void +android_glReadPixels__IIIIIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jobject pixels_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pixels = (GLvoid *) 0; + + pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining); + glReadPixels( + (GLint)x, + (GLint)y, + (GLsizei)width, + (GLsizei)height, + (GLenum)format, + (GLenum)type, + (GLvoid *)pixels + ); + if (_array) { + releasePointer(_env, _array, pixels, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) */ +static void +android_glRotatef__FFFF + (JNIEnv *_env, jobject _this, jfloat angle, jfloat x, jfloat y, jfloat z) { + glRotatef( + (GLfloat)angle, + (GLfloat)x, + (GLfloat)y, + (GLfloat)z + ); +} + +/* void glRotatex ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) */ +static void +android_glRotatex__IIII + (JNIEnv *_env, jobject _this, jint angle, jint x, jint y, jint z) { + glRotatex( + (GLfixed)angle, + (GLfixed)x, + (GLfixed)y, + (GLfixed)z + ); +} + +/* void glSampleCoverage ( GLclampf value, GLboolean invert ) */ +static void +android_glSampleCoverage__FZ + (JNIEnv *_env, jobject _this, jfloat value, jboolean invert) { + glSampleCoverage( + (GLclampf)value, + (GLboolean)invert + ); +} + +/* void glSampleCoveragex ( GLclampx value, GLboolean invert ) */ +static void +android_glSampleCoveragex__IZ + (JNIEnv *_env, jobject _this, jint value, jboolean invert) { + glSampleCoveragex( + (GLclampx)value, + (GLboolean)invert + ); +} + +/* void glScalef ( GLfloat x, GLfloat y, GLfloat z ) */ +static void +android_glScalef__FFF + (JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z) { + glScalef( + (GLfloat)x, + (GLfloat)y, + (GLfloat)z + ); +} + +/* void glScalex ( GLfixed x, GLfixed y, GLfixed z ) */ +static void +android_glScalex__III + (JNIEnv *_env, jobject _this, jint x, jint y, jint z) { + glScalex( + (GLfixed)x, + (GLfixed)y, + (GLfixed)z + ); +} + +/* void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height ) */ +static void +android_glScissor__IIII + (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height) { + glScissor( + (GLint)x, + (GLint)y, + (GLsizei)width, + (GLsizei)height + ); +} + +/* void glShadeModel ( GLenum mode ) */ +static void +android_glShadeModel__I + (JNIEnv *_env, jobject _this, jint mode) { + glShadeModel( + (GLenum)mode + ); +} + +/* void glStencilFunc ( GLenum func, GLint ref, GLuint mask ) */ +static void +android_glStencilFunc__III + (JNIEnv *_env, jobject _this, jint func, jint ref, jint mask) { + glStencilFunc( + (GLenum)func, + (GLint)ref, + (GLuint)mask + ); +} + +/* void glStencilMask ( GLuint mask ) */ +static void +android_glStencilMask__I + (JNIEnv *_env, jobject _this, jint mask) { + glStencilMask( + (GLuint)mask + ); +} + +/* void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass ) */ +static void +android_glStencilOp__III + (JNIEnv *_env, jobject _this, jint fail, jint zfail, jint zpass) { + glStencilOp( + (GLenum)fail, + (GLenum)zfail, + (GLenum)zpass + ); +} + +/* void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */ +static void +android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pointer = (GLvoid *) 0; + + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } + glTexCoordPointerBounds( + (GLint)size, + (GLenum)type, + (GLsizei)stride, + (GLvoid *)pointer, + (GLsizei)remaining + ); +} + +/* void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) */ +static void +android_glTexEnvf__IIF + (JNIEnv *_env, jobject _this, jint target, jint pname, jfloat param) { + glTexEnvf( + (GLenum)target, + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) */ +static void +android_glTexEnvfv__II_3FI + (JNIEnv *_env, jobject _this, jint target, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexEnvfv( + (GLenum)target, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) */ +static void +android_glTexEnvfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glTexEnvfv( + (GLenum)target, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexEnvx ( GLenum target, GLenum pname, GLfixed param ) */ +static void +android_glTexEnvx__III + (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) { + glTexEnvx( + (GLenum)target, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexEnvxv__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexEnvxv( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexEnvxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glTexEnvxv( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) */ +static void +android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint format, jint type, jobject pixels_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pixels = (GLvoid *) 0; + + if (pixels_buf) { + pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining); + } + glTexImage2D( + (GLenum)target, + (GLint)level, + (GLint)internalformat, + (GLsizei)width, + (GLsizei)height, + (GLint)border, + (GLenum)format, + (GLenum)type, + (GLvoid *)pixels + ); + if (_array) { + releasePointer(_env, _array, pixels, JNI_FALSE); + } +} + +/* void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) */ +static void +android_glTexParameterf__IIF + (JNIEnv *_env, jobject _this, jint target, jint pname, jfloat param) { + glTexParameterf( + (GLenum)target, + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glTexParameterx ( GLenum target, GLenum pname, GLfixed param ) */ +static void +android_glTexParameterx__III + (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) { + 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 ) */ +static void +android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint type, jobject pixels_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pixels = (GLvoid *) 0; + + if (pixels_buf) { + pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining); + } + glTexSubImage2D( + (GLenum)target, + (GLint)level, + (GLint)xoffset, + (GLint)yoffset, + (GLsizei)width, + (GLsizei)height, + (GLenum)format, + (GLenum)type, + (GLvoid *)pixels + ); + if (_array) { + releasePointer(_env, _array, pixels, JNI_FALSE); + } +} + +/* void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) */ +static void +android_glTranslatef__FFF + (JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z) { + glTranslatef( + (GLfloat)x, + (GLfloat)y, + (GLfloat)z + ); +} + +/* void glTranslatex ( GLfixed x, GLfixed y, GLfixed z ) */ +static void +android_glTranslatex__III + (JNIEnv *_env, jobject _this, jint x, jint y, jint z) { + glTranslatex( + (GLfixed)x, + (GLfixed)y, + (GLfixed)z + ); +} + +/* void glVertexPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */ +static void +android_glVertexPointerBounds__IIILjava_nio_Buffer_2I + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pointer = (GLvoid *) 0; + + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } + glVertexPointerBounds( + (GLint)size, + (GLenum)type, + (GLsizei)stride, + (GLvoid *)pointer, + (GLsizei)remaining + ); +} + +/* void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) */ +static void +android_glViewport__IIII + (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height) { + glViewport( + (GLint)x, + (GLint)y, + (GLsizei)width, + (GLsizei)height + ); +} + +static const char *classPathName = "android/opengl/GLES10"; + +static JNINativeMethod methods[] = { +{"_nativeClassInit", "()V", (void*)nativeClassInit }, +{"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I }, +{"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF }, +{"glAlphaFuncx", "(II)V", (void *) android_glAlphaFuncx__II }, +{"glBindTexture", "(II)V", (void *) android_glBindTexture__II }, +{"glBlendFunc", "(II)V", (void *) android_glBlendFunc__II }, +{"glClear", "(I)V", (void *) android_glClear__I }, +{"glClearColor", "(FFFF)V", (void *) android_glClearColor__FFFF }, +{"glClearColorx", "(IIII)V", (void *) android_glClearColorx__IIII }, +{"glClearDepthf", "(F)V", (void *) android_glClearDepthf__F }, +{"glClearDepthx", "(I)V", (void *) android_glClearDepthx__I }, +{"glClearStencil", "(I)V", (void *) android_glClearStencil__I }, +{"glClientActiveTexture", "(I)V", (void *) android_glClientActiveTexture__I }, +{"glColor4f", "(FFFF)V", (void *) android_glColor4f__FFFF }, +{"glColor4x", "(IIII)V", (void *) android_glColor4x__IIII }, +{"glColorMask", "(ZZZZ)V", (void *) android_glColorMask__ZZZZ }, +{"glColorPointerBounds", "(IIILjava/nio/Buffer;I)V", (void *) android_glColorPointerBounds__IIILjava_nio_Buffer_2I }, +{"glCompressedTexImage2D", "(IIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2 }, +{"glCompressedTexSubImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 }, +{"glCopyTexImage2D", "(IIIIIIII)V", (void *) android_glCopyTexImage2D__IIIIIIII }, +{"glCopyTexSubImage2D", "(IIIIIIII)V", (void *) android_glCopyTexSubImage2D__IIIIIIII }, +{"glCullFace", "(I)V", (void *) android_glCullFace__I }, +{"glDeleteTextures", "(I[II)V", (void *) android_glDeleteTextures__I_3II }, +{"glDeleteTextures", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteTextures__ILjava_nio_IntBuffer_2 }, +{"glDepthFunc", "(I)V", (void *) android_glDepthFunc__I }, +{"glDepthMask", "(Z)V", (void *) android_glDepthMask__Z }, +{"glDepthRangef", "(FF)V", (void *) android_glDepthRangef__FF }, +{"glDepthRangex", "(II)V", (void *) android_glDepthRangex__II }, +{"glDisable", "(I)V", (void *) android_glDisable__I }, +{"glDisableClientState", "(I)V", (void *) android_glDisableClientState__I }, +{"glDrawArrays", "(III)V", (void *) android_glDrawArrays__III }, +{"glDrawElements", "(IIILjava/nio/Buffer;)V", (void *) android_glDrawElements__IIILjava_nio_Buffer_2 }, +{"glEnable", "(I)V", (void *) android_glEnable__I }, +{"glEnableClientState", "(I)V", (void *) android_glEnableClientState__I }, +{"glFinish", "()V", (void *) android_glFinish__ }, +{"glFlush", "()V", (void *) android_glFlush__ }, +{"glFogf", "(IF)V", (void *) android_glFogf__IF }, +{"glFogfv", "(I[FI)V", (void *) android_glFogfv__I_3FI }, +{"glFogfv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glFogfv__ILjava_nio_FloatBuffer_2 }, +{"glFogx", "(II)V", (void *) android_glFogx__II }, +{"glFogxv", "(I[II)V", (void *) android_glFogxv__I_3II }, +{"glFogxv", "(ILjava/nio/IntBuffer;)V", (void *) android_glFogxv__ILjava_nio_IntBuffer_2 }, +{"glFrontFace", "(I)V", (void *) android_glFrontFace__I }, +{"glFrustumf", "(FFFFFF)V", (void *) android_glFrustumf__FFFFFF }, +{"glFrustumx", "(IIIIII)V", (void *) android_glFrustumx__IIIIII }, +{"glGenTextures", "(I[II)V", (void *) android_glGenTextures__I_3II }, +{"glGenTextures", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenTextures__ILjava_nio_IntBuffer_2 }, +{"glGetError", "()I", (void *) android_glGetError__ }, +{"glGetIntegerv", "(I[II)V", (void *) android_glGetIntegerv__I_3II }, +{"glGetIntegerv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetIntegerv__ILjava_nio_IntBuffer_2 }, +{"glGetString", "(I)Ljava/lang/String;", (void *) android_glGetString }, +{"glHint", "(II)V", (void *) android_glHint__II }, +{"glLightModelf", "(IF)V", (void *) android_glLightModelf__IF }, +{"glLightModelfv", "(I[FI)V", (void *) android_glLightModelfv__I_3FI }, +{"glLightModelfv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glLightModelfv__ILjava_nio_FloatBuffer_2 }, +{"glLightModelx", "(II)V", (void *) android_glLightModelx__II }, +{"glLightModelxv", "(I[II)V", (void *) android_glLightModelxv__I_3II }, +{"glLightModelxv", "(ILjava/nio/IntBuffer;)V", (void *) android_glLightModelxv__ILjava_nio_IntBuffer_2 }, +{"glLightf", "(IIF)V", (void *) android_glLightf__IIF }, +{"glLightfv", "(II[FI)V", (void *) android_glLightfv__II_3FI }, +{"glLightfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glLightfv__IILjava_nio_FloatBuffer_2 }, +{"glLightx", "(III)V", (void *) android_glLightx__III }, +{"glLightxv", "(II[II)V", (void *) android_glLightxv__II_3II }, +{"glLightxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glLightxv__IILjava_nio_IntBuffer_2 }, +{"glLineWidth", "(F)V", (void *) android_glLineWidth__F }, +{"glLineWidthx", "(I)V", (void *) android_glLineWidthx__I }, +{"glLoadIdentity", "()V", (void *) android_glLoadIdentity__ }, +{"glLoadMatrixf", "([FI)V", (void *) android_glLoadMatrixf___3FI }, +{"glLoadMatrixf", "(Ljava/nio/FloatBuffer;)V", (void *) android_glLoadMatrixf__Ljava_nio_FloatBuffer_2 }, +{"glLoadMatrixx", "([II)V", (void *) android_glLoadMatrixx___3II }, +{"glLoadMatrixx", "(Ljava/nio/IntBuffer;)V", (void *) android_glLoadMatrixx__Ljava_nio_IntBuffer_2 }, +{"glLogicOp", "(I)V", (void *) android_glLogicOp__I }, +{"glMaterialf", "(IIF)V", (void *) android_glMaterialf__IIF }, +{"glMaterialfv", "(II[FI)V", (void *) android_glMaterialfv__II_3FI }, +{"glMaterialfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glMaterialfv__IILjava_nio_FloatBuffer_2 }, +{"glMaterialx", "(III)V", (void *) android_glMaterialx__III }, +{"glMaterialxv", "(II[II)V", (void *) android_glMaterialxv__II_3II }, +{"glMaterialxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glMaterialxv__IILjava_nio_IntBuffer_2 }, +{"glMatrixMode", "(I)V", (void *) android_glMatrixMode__I }, +{"glMultMatrixf", "([FI)V", (void *) android_glMultMatrixf___3FI }, +{"glMultMatrixf", "(Ljava/nio/FloatBuffer;)V", (void *) android_glMultMatrixf__Ljava_nio_FloatBuffer_2 }, +{"glMultMatrixx", "([II)V", (void *) android_glMultMatrixx___3II }, +{"glMultMatrixx", "(Ljava/nio/IntBuffer;)V", (void *) android_glMultMatrixx__Ljava_nio_IntBuffer_2 }, +{"glMultiTexCoord4f", "(IFFFF)V", (void *) android_glMultiTexCoord4f__IFFFF }, +{"glMultiTexCoord4x", "(IIIII)V", (void *) android_glMultiTexCoord4x__IIIII }, +{"glNormal3f", "(FFF)V", (void *) android_glNormal3f__FFF }, +{"glNormal3x", "(III)V", (void *) android_glNormal3x__III }, +{"glNormalPointerBounds", "(IILjava/nio/Buffer;I)V", (void *) android_glNormalPointerBounds__IILjava_nio_Buffer_2I }, +{"glOrthof", "(FFFFFF)V", (void *) android_glOrthof__FFFFFF }, +{"glOrthox", "(IIIIII)V", (void *) android_glOrthox__IIIIII }, +{"glPixelStorei", "(II)V", (void *) android_glPixelStorei__II }, +{"glPointSize", "(F)V", (void *) android_glPointSize__F }, +{"glPointSizex", "(I)V", (void *) android_glPointSizex__I }, +{"glPolygonOffset", "(FF)V", (void *) android_glPolygonOffset__FF }, +{"glPolygonOffsetx", "(II)V", (void *) android_glPolygonOffsetx__II }, +{"glPopMatrix", "()V", (void *) android_glPopMatrix__ }, +{"glPushMatrix", "()V", (void *) android_glPushMatrix__ }, +{"glReadPixels", "(IIIIIILjava/nio/Buffer;)V", (void *) android_glReadPixels__IIIIIILjava_nio_Buffer_2 }, +{"glRotatef", "(FFFF)V", (void *) android_glRotatef__FFFF }, +{"glRotatex", "(IIII)V", (void *) android_glRotatex__IIII }, +{"glSampleCoverage", "(FZ)V", (void *) android_glSampleCoverage__FZ }, +{"glSampleCoveragex", "(IZ)V", (void *) android_glSampleCoveragex__IZ }, +{"glScalef", "(FFF)V", (void *) android_glScalef__FFF }, +{"glScalex", "(III)V", (void *) android_glScalex__III }, +{"glScissor", "(IIII)V", (void *) android_glScissor__IIII }, +{"glShadeModel", "(I)V", (void *) android_glShadeModel__I }, +{"glStencilFunc", "(III)V", (void *) android_glStencilFunc__III }, +{"glStencilMask", "(I)V", (void *) android_glStencilMask__I }, +{"glStencilOp", "(III)V", (void *) android_glStencilOp__III }, +{"glTexCoordPointerBounds", "(IIILjava/nio/Buffer;I)V", (void *) android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I }, +{"glTexEnvf", "(IIF)V", (void *) android_glTexEnvf__IIF }, +{"glTexEnvfv", "(II[FI)V", (void *) android_glTexEnvfv__II_3FI }, +{"glTexEnvfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glTexEnvfv__IILjava_nio_FloatBuffer_2 }, +{"glTexEnvx", "(III)V", (void *) android_glTexEnvx__III }, +{"glTexEnvxv", "(II[II)V", (void *) android_glTexEnvxv__II_3II }, +{"glTexEnvxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexEnvxv__IILjava_nio_IntBuffer_2 }, +{"glTexImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2 }, +{"glTexParameterf", "(IIF)V", (void *) android_glTexParameterf__IIF }, +{"glTexParameterx", "(III)V", (void *) android_glTexParameterx__III }, +{"glTexSubImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 }, +{"glTranslatef", "(FFF)V", (void *) android_glTranslatef__FFF }, +{"glTranslatex", "(III)V", (void *) android_glTranslatex__III }, +{"glVertexPointerBounds", "(IIILjava/nio/Buffer;I)V", (void *) android_glVertexPointerBounds__IIILjava_nio_Buffer_2I }, +{"glViewport", "(IIII)V", (void *) android_glViewport__IIII }, +}; + +int register_android_opengl_jni_GLES10(JNIEnv *_env) +{ + int err; + err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods)); + return err; +} diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f17ef21a521ed95e8424ced02812b04fd86e2a1a --- /dev/null +++ b/core/jni/android_opengl_GLES10Ext.cpp @@ -0,0 +1,250 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +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. */ + +static 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); +} + +// -------------------------------------------------------------------------- + +/* GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) */ +static jint +android_glQueryMatrixxOES___3II_3II + (JNIEnv *_env, jobject _this, jintArray mantissa_ref, jint mantissaOffset, jintArray exponent_ref, jint exponentOffset) { + jint _exception = 0; + GLbitfield _returnValue = -1; + GLfixed *mantissa_base = (GLfixed *) 0; + jint _mantissaRemaining; + GLfixed *mantissa = (GLfixed *) 0; + GLint *exponent_base = (GLint *) 0; + jint _exponentRemaining; + GLint *exponent = (GLint *) 0; + + if (!mantissa_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "mantissa == null"); + goto exit; + } + if (mantissaOffset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "mantissaOffset < 0"); + goto exit; + } + _mantissaRemaining = _env->GetArrayLength(mantissa_ref) - mantissaOffset; + if (_mantissaRemaining < 16) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - mantissaOffset < 16"); + goto exit; + } + mantissa_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(mantissa_ref, (jboolean *)0); + mantissa = mantissa_base + mantissaOffset; + + if (!exponent_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "exponent == null"); + goto exit; + } + if (exponentOffset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "exponentOffset < 0"); + goto exit; + } + _exponentRemaining = _env->GetArrayLength(exponent_ref) - exponentOffset; + if (_exponentRemaining < 16) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - exponentOffset < 16"); + goto exit; + } + exponent_base = (GLint *) + _env->GetPrimitiveArrayCritical(exponent_ref, (jboolean *)0); + exponent = exponent_base + exponentOffset; + + _returnValue = glQueryMatrixxOES( + (GLfixed *)mantissa, + (GLint *)exponent + ); + +exit: + if (exponent_base) { + _env->ReleasePrimitiveArrayCritical(exponent_ref, exponent_base, + _exception ? JNI_ABORT: 0); + } + if (mantissa_base) { + _env->ReleasePrimitiveArrayCritical(mantissa_ref, mantissa_base, + _exception ? JNI_ABORT: 0); + } + return _returnValue; +} + +/* GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) */ +static jint +android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jobject mantissa_buf, jobject exponent_buf) { + jint _exception = 0; + jarray _mantissaArray = (jarray) 0; + jarray _exponentArray = (jarray) 0; + GLbitfield _returnValue = -1; + jint _mantissaRemaining; + GLfixed *mantissa = (GLfixed *) 0; + jint _exponentRemaining; + GLint *exponent = (GLint *) 0; + + mantissa = (GLfixed *)getPointer(_env, mantissa_buf, &_mantissaArray, &_mantissaRemaining); + if (_mantissaRemaining < 16) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < 16"); + goto exit; + } + exponent = (GLint *)getPointer(_env, exponent_buf, &_exponentArray, &_exponentRemaining); + if (_exponentRemaining < 16) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < 16"); + goto exit; + } + _returnValue = glQueryMatrixxOES( + (GLfixed *)mantissa, + (GLint *)exponent + ); + +exit: + if (_mantissaArray) { + releasePointer(_env, _mantissaArray, exponent, _exception ? JNI_FALSE : JNI_TRUE); + } + if (_exponentArray) { + releasePointer(_env, _exponentArray, mantissa, _exception ? JNI_FALSE : JNI_TRUE); + } + return _returnValue; +} + +static const char *classPathName = "android/opengl/GLES10Ext"; + +static JNINativeMethod methods[] = { +{"_nativeClassInit", "()V", (void*)nativeClassInit }, +{"glQueryMatrixxOES", "([II[II)I", (void *) android_glQueryMatrixxOES___3II_3II }, +{"glQueryMatrixxOES", "(Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)I", (void *) android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 }, +}; + +int register_android_opengl_jni_GLES10Ext(JNIEnv *_env) +{ + int err; + err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods)); + return err; +} diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed8dfc8b955dbbb8e716d4e410f9467b81db9875 --- /dev/null +++ b/core/jni/android_opengl_GLES11.cpp @@ -0,0 +1,2465 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +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. */ + +static 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); +} + +// -------------------------------------------------------------------------- + +/* void glBindBuffer ( GLenum target, GLuint buffer ) */ +static void +android_glBindBuffer__II + (JNIEnv *_env, jobject _this, jint target, jint buffer) { + glBindBuffer( + (GLenum)target, + (GLuint)buffer + ); +} + +/* void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) */ +static void +android_glBufferData__IILjava_nio_Buffer_2I + (JNIEnv *_env, jobject _this, jint target, jint size, jobject data_buf, jint usage) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *data = (GLvoid *) 0; + + if (data_buf) { + data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining); + } + glBufferData( + (GLenum)target, + (GLsizeiptr)size, + (GLvoid *)data, + (GLenum)usage + ); + if (_array) { + releasePointer(_env, _array, data, JNI_FALSE); + } +} + +/* void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data ) */ +static void +android_glBufferSubData__IIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint target, jint offset, jint size, jobject data_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *data = (GLvoid *) 0; + + data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining); + glBufferSubData( + (GLenum)target, + (GLintptr)offset, + (GLsizeiptr)size, + (GLvoid *)data + ); + if (_array) { + releasePointer(_env, _array, data, JNI_FALSE); + } +} + +/* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ +static void +android_glClipPlanef__I_3FI + (JNIEnv *_env, jobject _this, jint plane, jfloatArray equation_ref, jint offset) { + GLfloat *equation_base = (GLfloat *) 0; + jint _remaining; + GLfloat *equation = (GLfloat *) 0; + + if (!equation_ref) { + _env->ThrowNew(IAEClass, "equation == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(equation_ref) - offset; + equation_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(equation_ref, (jboolean *)0); + equation = equation_base + offset; + + glClipPlanef( + (GLenum)plane, + (GLfloat *)equation + ); + +exit: + if (equation_base) { + _env->ReleasePrimitiveArrayCritical(equation_ref, equation_base, + JNI_ABORT); + } +} + +/* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ +static void +android_glClipPlanef__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *equation = (GLfloat *) 0; + + equation = (GLfloat *)getPointer(_env, equation_buf, &_array, &_remaining); + glClipPlanef( + (GLenum)plane, + (GLfloat *)equation + ); + if (_array) { + releasePointer(_env, _array, equation, JNI_FALSE); + } +} + +/* void glClipPlanex ( GLenum plane, const GLfixed *equation ) */ +static void +android_glClipPlanex__I_3II + (JNIEnv *_env, jobject _this, jint plane, jintArray equation_ref, jint offset) { + GLfixed *equation_base = (GLfixed *) 0; + jint _remaining; + GLfixed *equation = (GLfixed *) 0; + + if (!equation_ref) { + _env->ThrowNew(IAEClass, "equation == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(equation_ref) - offset; + equation_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(equation_ref, (jboolean *)0); + equation = equation_base + offset; + + glClipPlanex( + (GLenum)plane, + (GLfixed *)equation + ); + +exit: + if (equation_base) { + _env->ReleasePrimitiveArrayCritical(equation_ref, equation_base, + JNI_ABORT); + } +} + +/* void glClipPlanex ( GLenum plane, const GLfixed *equation ) */ +static void +android_glClipPlanex__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *equation = (GLfixed *) 0; + + equation = (GLfixed *)getPointer(_env, equation_buf, &_array, &_remaining); + glClipPlanex( + (GLenum)plane, + (GLfixed *)equation + ); + if (_array) { + releasePointer(_env, _array, equation, JNI_FALSE); + } +} + +/* void glColor4ub ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) */ +static void +android_glColor4ub__BBBB + (JNIEnv *_env, jobject _this, jbyte red, jbyte green, jbyte blue, jbyte alpha) { + glColor4ub( + (GLubyte)red, + (GLubyte)green, + (GLubyte)blue, + (GLubyte)alpha + ); +} + +/* void glColorPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */ +static void +android_glColorPointer__IIII + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) { + glColorPointer( + (GLint)size, + (GLenum)type, + (GLsizei)stride, + (const GLvoid *)offset + ); +} + +/* void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) */ +static void +android_glDeleteBuffers__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray buffers_ref, jint offset) { + GLuint *buffers_base = (GLuint *) 0; + jint _remaining; + GLuint *buffers = (GLuint *) 0; + + if (!buffers_ref) { + _env->ThrowNew(IAEClass, "buffers == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(buffers_ref) - offset; + if (_remaining < n) { + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + buffers_base = (GLuint *) + _env->GetPrimitiveArrayCritical(buffers_ref, (jboolean *)0); + buffers = buffers_base + offset; + + glDeleteBuffers( + (GLsizei)n, + (GLuint *)buffers + ); + +exit: + if (buffers_base) { + _env->ReleasePrimitiveArrayCritical(buffers_ref, buffers_base, + JNI_ABORT); + } +} + +/* void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) */ +static void +android_glDeleteBuffers__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject buffers_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLuint *buffers = (GLuint *) 0; + + buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining); + if (_remaining < n) { + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glDeleteBuffers( + (GLsizei)n, + (GLuint *)buffers + ); + +exit: + if (_array) { + releasePointer(_env, _array, buffers, JNI_FALSE); + } +} + +/* void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset ) */ +static void +android_glDrawElements__IIII + (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jint offset) { + glDrawElements( + (GLenum)mode, + (GLsizei)count, + (GLenum)type, + (const GLvoid *)offset + ); +} + +/* void glGenBuffers ( GLsizei n, GLuint *buffers ) */ +static void +android_glGenBuffers__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray buffers_ref, jint offset) { + jint _exception = 0; + GLuint *buffers_base = (GLuint *) 0; + jint _remaining; + GLuint *buffers = (GLuint *) 0; + + if (!buffers_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "buffers == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(buffers_ref) - offset; + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + buffers_base = (GLuint *) + _env->GetPrimitiveArrayCritical(buffers_ref, (jboolean *)0); + buffers = buffers_base + offset; + + glGenBuffers( + (GLsizei)n, + (GLuint *)buffers + ); + +exit: + if (buffers_base) { + _env->ReleasePrimitiveArrayCritical(buffers_ref, buffers_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGenBuffers ( GLsizei n, GLuint *buffers ) */ +static void +android_glGenBuffers__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject buffers_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLuint *buffers = (GLuint *) 0; + + buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining); + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glGenBuffers( + (GLsizei)n, + (GLuint *)buffers + ); + +exit: + if (_array) { + releasePointer(_env, _array, buffers, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetBooleanv ( GLenum pname, GLboolean *params ) */ +static void +android_glGetBooleanv__I_3ZI + (JNIEnv *_env, jobject _this, jint pname, jbooleanArray params_ref, jint offset) { + jint _exception = 0; + GLboolean *params_base = (GLboolean *) 0; + jint _remaining; + GLboolean *params = (GLboolean *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLboolean *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetBooleanv( + (GLenum)pname, + (GLboolean *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetBooleanv ( GLenum pname, GLboolean *params ) */ +static void +android_glGetBooleanv__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLboolean *params = (GLboolean *) 0; + + params = (GLboolean *)getPointer(_env, params_buf, &_array, &_remaining); + glGetBooleanv( + (GLenum)pname, + (GLboolean *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */ +static void +android_glGetBufferParameteriv__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + _env->ThrowNew(UOEClass, + "glGetBufferParameteriv"); +} + +/* void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */ +static void +android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + _env->ThrowNew(UOEClass, + "glGetBufferParameteriv"); +} + +/* void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) */ +static void +android_glGetClipPlanef__I_3FI + (JNIEnv *_env, jobject _this, jint pname, jfloatArray eqn_ref, jint offset) { + jint _exception = 0; + GLfloat *eqn_base = (GLfloat *) 0; + jint _remaining; + GLfloat *eqn = (GLfloat *) 0; + + if (!eqn_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "eqn == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(eqn_ref) - offset; + eqn_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(eqn_ref, (jboolean *)0); + eqn = eqn_base + offset; + + glGetClipPlanef( + (GLenum)pname, + (GLfloat *)eqn + ); + +exit: + if (eqn_base) { + _env->ReleasePrimitiveArrayCritical(eqn_ref, eqn_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) */ +static void +android_glGetClipPlanef__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *eqn = (GLfloat *) 0; + + eqn = (GLfloat *)getPointer(_env, eqn_buf, &_array, &_remaining); + glGetClipPlanef( + (GLenum)pname, + (GLfloat *)eqn + ); + if (_array) { + releasePointer(_env, _array, eqn, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) */ +static void +android_glGetClipPlanex__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray eqn_ref, jint offset) { + jint _exception = 0; + GLfixed *eqn_base = (GLfixed *) 0; + jint _remaining; + GLfixed *eqn = (GLfixed *) 0; + + if (!eqn_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "eqn == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(eqn_ref) - offset; + eqn_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(eqn_ref, (jboolean *)0); + eqn = eqn_base + offset; + + glGetClipPlanex( + (GLenum)pname, + (GLfixed *)eqn + ); + +exit: + if (eqn_base) { + _env->ReleasePrimitiveArrayCritical(eqn_ref, eqn_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) */ +static void +android_glGetClipPlanex__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *eqn = (GLfixed *) 0; + + eqn = (GLfixed *)getPointer(_env, eqn_buf, &_array, &_remaining); + glGetClipPlanex( + (GLenum)pname, + (GLfixed *)eqn + ); + if (_array) { + releasePointer(_env, _array, eqn, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetFixedv ( GLenum pname, GLfixed *params ) */ +static void +android_glGetFixedv__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetFixedv( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetFixedv ( GLenum pname, GLfixed *params ) */ +static void +android_glGetFixedv__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glGetFixedv( + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetFloatv ( GLenum pname, GLfloat *params ) */ +static void +android_glGetFloatv__I_3FI + (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) { + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetFloatv( + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetFloatv ( GLenum pname, GLfloat *params ) */ +static void +android_glGetFloatv__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + glGetFloatv( + (GLenum)pname, + (GLfloat *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) */ +static void +android_glGetLightfv__II_3FI + (JNIEnv *_env, jobject _this, jint light, jint pname, jfloatArray params_ref, jint offset) { + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetLightfv( + (GLenum)light, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) */ +static void +android_glGetLightfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetLightfv( + (GLenum)light, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) */ +static void +android_glGetLightxv__II_3II + (JNIEnv *_env, jobject _this, jint light, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetLightxv( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) */ +static void +android_glGetLightxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SPOT_EXPONENT) + case GL_SPOT_EXPONENT: +#endif // defined(GL_SPOT_EXPONENT) +#if defined(GL_SPOT_CUTOFF) + case GL_SPOT_CUTOFF: +#endif // defined(GL_SPOT_CUTOFF) +#if defined(GL_CONSTANT_ATTENUATION) + case GL_CONSTANT_ATTENUATION: +#endif // defined(GL_CONSTANT_ATTENUATION) +#if defined(GL_LINEAR_ATTENUATION) + case GL_LINEAR_ATTENUATION: +#endif // defined(GL_LINEAR_ATTENUATION) +#if defined(GL_QUADRATIC_ATTENUATION) + case GL_QUADRATIC_ATTENUATION: +#endif // defined(GL_QUADRATIC_ATTENUATION) + _needed = 1; + break; +#if defined(GL_SPOT_DIRECTION) + case GL_SPOT_DIRECTION: +#endif // defined(GL_SPOT_DIRECTION) + _needed = 3; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetLightxv( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) */ +static void +android_glGetMaterialfv__II_3FI + (JNIEnv *_env, jobject _this, jint face, jint pname, jfloatArray params_ref, jint offset) { + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetMaterialfv( + (GLenum)face, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) */ +static void +android_glGetMaterialfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetMaterialfv( + (GLenum)face, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) */ +static void +android_glGetMaterialxv__II_3II + (JNIEnv *_env, jobject _this, jint face, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetMaterialxv( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) */ +static void +android_glGetMaterialxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_SHININESS) + case GL_SHININESS: +#endif // defined(GL_SHININESS) + _needed = 1; + break; +#if defined(GL_AMBIENT) + case GL_AMBIENT: +#endif // defined(GL_AMBIENT) +#if defined(GL_DIFFUSE) + case GL_DIFFUSE: +#endif // defined(GL_DIFFUSE) +#if defined(GL_SPECULAR) + case GL_SPECULAR: +#endif // defined(GL_SPECULAR) +#if defined(GL_EMISSION) + case GL_EMISSION: +#endif // defined(GL_EMISSION) +#if defined(GL_AMBIENT_AND_DIFFUSE) + case GL_AMBIENT_AND_DIFFUSE: +#endif // defined(GL_AMBIENT_AND_DIFFUSE) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetMaterialxv( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexEnvfv ( GLenum env, GLenum pname, GLfloat *params ) */ +static void +android_glGetTexEnvfv__II_3FI + (JNIEnv *_env, jobject _this, jint env, jint pname, jfloatArray params_ref, jint offset) { + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexEnvfv( + (GLenum)env, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexEnvfv ( GLenum env, GLenum pname, GLfloat *params ) */ +static void +android_glGetTexEnvfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint env, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetTexEnvfv( + (GLenum)env, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) */ +static void +android_glGetTexEnviv__II_3II + (JNIEnv *_env, jobject _this, jint env, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexEnviv( + (GLenum)env, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) */ +static void +android_glGetTexEnviv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint env, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetTexEnviv( + (GLenum)env, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexEnvxv__II_3II + (JNIEnv *_env, jobject _this, jint env, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexEnvxv( + (GLenum)env, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexEnvxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint env, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glGetTexEnvxv( + (GLenum)env, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) */ +static void +android_glGetTexParameterfv__II_3FI + (JNIEnv *_env, jobject _this, jint target, jint pname, jfloatArray params_ref, jint offset) { + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexParameterfv( + (GLenum)target, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) */ +static void +android_glGetTexParameterfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glGetTexParameterfv( + (GLenum)target, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) */ +static void +android_glGetTexParameteriv__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexParameteriv( + (GLenum)target, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) */ +static void +android_glGetTexParameteriv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glGetTexParameteriv( + (GLenum)target, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexParameterxv__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexParameterxv( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexParameterxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glGetTexParameterxv( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* GLboolean glIsBuffer ( GLuint buffer ) */ +static jboolean +android_glIsBuffer__I + (JNIEnv *_env, jobject _this, jint buffer) { + GLboolean _returnValue; + _returnValue = glIsBuffer( + (GLuint)buffer + ); + return _returnValue; +} + +/* GLboolean glIsEnabled ( GLenum cap ) */ +static jboolean +android_glIsEnabled__I + (JNIEnv *_env, jobject _this, jint cap) { + GLboolean _returnValue; + _returnValue = glIsEnabled( + (GLenum)cap + ); + return _returnValue; +} + +/* GLboolean glIsTexture ( GLuint texture ) */ +static jboolean +android_glIsTexture__I + (JNIEnv *_env, jobject _this, jint texture) { + GLboolean _returnValue; + _returnValue = glIsTexture( + (GLuint)texture + ); + return _returnValue; +} + +/* void glNormalPointer ( GLenum type, GLsizei stride, GLint offset ) */ +static void +android_glNormalPointer__III + (JNIEnv *_env, jobject _this, jint type, jint stride, jint offset) { + glNormalPointer( + (GLenum)type, + (GLsizei)stride, + (const GLvoid *)offset + ); +} + +/* void glPointParameterf ( GLenum pname, GLfloat param ) */ +static void +android_glPointParameterf__IF + (JNIEnv *_env, jobject _this, jint pname, jfloat param) { + glPointParameterf( + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glPointParameterfv ( GLenum pname, const GLfloat *params ) */ +static void +android_glPointParameterfv__I_3FI + (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glPointParameterfv( + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glPointParameterfv ( GLenum pname, const GLfloat *params ) */ +static void +android_glPointParameterfv__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glPointParameterfv( + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glPointParameterx ( GLenum pname, GLfixed param ) */ +static void +android_glPointParameterx__II + (JNIEnv *_env, jobject _this, jint pname, jint param) { + glPointParameterx( + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glPointParameterxv ( GLenum pname, const GLfixed *params ) */ +static void +android_glPointParameterxv__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glPointParameterxv( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glPointParameterxv ( GLenum pname, const GLfixed *params ) */ +static void +android_glPointParameterxv__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glPointParameterxv( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glPointSizePointerOES ( GLenum type, GLsizei stride, const GLvoid *pointer ) */ +static void +android_glPointSizePointerOES__IILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLvoid *pointer = (GLvoid *) 0; + + pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining); + glPointSizePointerOES( + (GLenum)type, + (GLsizei)stride, + (GLvoid *)pointer + ); + if (_array) { + releasePointer(_env, _array, pointer, JNI_FALSE); + } +} + +/* void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */ +static void +android_glTexCoordPointer__IIII + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) { + glTexCoordPointer( + (GLint)size, + (GLenum)type, + (GLsizei)stride, + (const GLvoid *)offset + ); +} + +/* void glTexEnvi ( GLenum target, GLenum pname, GLint param ) */ +static void +android_glTexEnvi__III + (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) { + glTexEnvi( + (GLenum)target, + (GLenum)pname, + (GLint)param + ); +} + +/* void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) */ +static void +android_glTexEnviv__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "length - offset < needed"); + goto exit; + } + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexEnviv( + (GLenum)target, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) */ +static void +android_glTexEnviv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + int _needed; + switch (pname) { +#if defined(GL_TEXTURE_ENV_MODE) + case GL_TEXTURE_ENV_MODE: +#endif // defined(GL_TEXTURE_ENV_MODE) +#if defined(GL_COMBINE_RGB) + case GL_COMBINE_RGB: +#endif // defined(GL_COMBINE_RGB) +#if defined(GL_COMBINE_ALPHA) + case GL_COMBINE_ALPHA: +#endif // defined(GL_COMBINE_ALPHA) + _needed = 1; + break; +#if defined(GL_TEXTURE_ENV_COLOR) + case GL_TEXTURE_ENV_COLOR: +#endif // defined(GL_TEXTURE_ENV_COLOR) + _needed = 4; + break; + default: + _needed = 0; + break; + } + if (_remaining < _needed) { + _env->ThrowNew(IAEClass, "remaining() < needed"); + goto exit; + } + glTexEnviv( + (GLenum)target, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) */ +static void +android_glTexParameterfv__II_3FI + (JNIEnv *_env, jobject _this, jint target, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexParameterfv( + (GLenum)target, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) */ +static void +android_glTexParameterfv__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glTexParameterfv( + (GLenum)target, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexParameteri ( GLenum target, GLenum pname, GLint param ) */ +static void +android_glTexParameteri__III + (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) { + glTexParameteri( + (GLenum)target, + (GLenum)pname, + (GLint)param + ); +} + +/* void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) */ +static void +android_glTexParameteriv__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexParameteriv( + (GLenum)target, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) */ +static void +android_glTexParameteriv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glTexParameteriv( + (GLenum)target, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexParameterxv__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "length - offset < 1"); + goto exit; + } + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexParameterxv( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexParameterxv__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + if (_remaining < 1) { + _env->ThrowNew(IAEClass, "remaining() < 1"); + goto exit; + } + glTexParameterxv( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glVertexPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */ +static void +android_glVertexPointer__IIII + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) { + glVertexPointer( + (GLint)size, + (GLenum)type, + (GLsizei)stride, + (const GLvoid *)offset + ); +} + +static const char *classPathName = "android/opengl/GLES11"; + +static JNINativeMethod methods[] = { +{"_nativeClassInit", "()V", (void*)nativeClassInit }, +{"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II }, +{"glBufferData", "(IILjava/nio/Buffer;I)V", (void *) android_glBufferData__IILjava_nio_Buffer_2I }, +{"glBufferSubData", "(IIILjava/nio/Buffer;)V", (void *) android_glBufferSubData__IIILjava_nio_Buffer_2 }, +{"glClipPlanef", "(I[FI)V", (void *) android_glClipPlanef__I_3FI }, +{"glClipPlanef", "(ILjava/nio/FloatBuffer;)V", (void *) android_glClipPlanef__ILjava_nio_FloatBuffer_2 }, +{"glClipPlanex", "(I[II)V", (void *) android_glClipPlanex__I_3II }, +{"glClipPlanex", "(ILjava/nio/IntBuffer;)V", (void *) android_glClipPlanex__ILjava_nio_IntBuffer_2 }, +{"glColor4ub", "(BBBB)V", (void *) android_glColor4ub__BBBB }, +{"glColorPointer", "(IIII)V", (void *) android_glColorPointer__IIII }, +{"glDeleteBuffers", "(I[II)V", (void *) android_glDeleteBuffers__I_3II }, +{"glDeleteBuffers", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteBuffers__ILjava_nio_IntBuffer_2 }, +{"glDrawElements", "(IIII)V", (void *) android_glDrawElements__IIII }, +{"glGenBuffers", "(I[II)V", (void *) android_glGenBuffers__I_3II }, +{"glGenBuffers", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenBuffers__ILjava_nio_IntBuffer_2 }, +{"glGetBooleanv", "(I[ZI)V", (void *) android_glGetBooleanv__I_3ZI }, +{"glGetBooleanv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetBooleanv__ILjava_nio_IntBuffer_2 }, +{"glGetBufferParameteriv", "(II[II)V", (void *) android_glGetBufferParameteriv__II_3II }, +{"glGetBufferParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2 }, +{"glGetClipPlanef", "(I[FI)V", (void *) android_glGetClipPlanef__I_3FI }, +{"glGetClipPlanef", "(ILjava/nio/FloatBuffer;)V", (void *) android_glGetClipPlanef__ILjava_nio_FloatBuffer_2 }, +{"glGetClipPlanex", "(I[II)V", (void *) android_glGetClipPlanex__I_3II }, +{"glGetClipPlanex", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetClipPlanex__ILjava_nio_IntBuffer_2 }, +{"glGetFixedv", "(I[II)V", (void *) android_glGetFixedv__I_3II }, +{"glGetFixedv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetFixedv__ILjava_nio_IntBuffer_2 }, +{"glGetFloatv", "(I[FI)V", (void *) android_glGetFloatv__I_3FI }, +{"glGetFloatv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glGetFloatv__ILjava_nio_FloatBuffer_2 }, +{"glGetLightfv", "(II[FI)V", (void *) android_glGetLightfv__II_3FI }, +{"glGetLightfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetLightfv__IILjava_nio_FloatBuffer_2 }, +{"glGetLightxv", "(II[II)V", (void *) android_glGetLightxv__II_3II }, +{"glGetLightxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetLightxv__IILjava_nio_IntBuffer_2 }, +{"glGetMaterialfv", "(II[FI)V", (void *) android_glGetMaterialfv__II_3FI }, +{"glGetMaterialfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetMaterialfv__IILjava_nio_FloatBuffer_2 }, +{"glGetMaterialxv", "(II[II)V", (void *) android_glGetMaterialxv__II_3II }, +{"glGetMaterialxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetMaterialxv__IILjava_nio_IntBuffer_2 }, +{"glGetTexEnvfv", "(II[FI)V", (void *) android_glGetTexEnvfv__II_3FI }, +{"glGetTexEnvfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetTexEnvfv__IILjava_nio_FloatBuffer_2 }, +{"glGetTexEnviv", "(II[II)V", (void *) android_glGetTexEnviv__II_3II }, +{"glGetTexEnviv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexEnviv__IILjava_nio_IntBuffer_2 }, +{"glGetTexEnvxv", "(II[II)V", (void *) android_glGetTexEnvxv__II_3II }, +{"glGetTexEnvxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexEnvxv__IILjava_nio_IntBuffer_2 }, +{"glGetTexParameterfv", "(II[FI)V", (void *) android_glGetTexParameterfv__II_3FI }, +{"glGetTexParameterfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetTexParameterfv__IILjava_nio_FloatBuffer_2 }, +{"glGetTexParameteriv", "(II[II)V", (void *) android_glGetTexParameteriv__II_3II }, +{"glGetTexParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameteriv__IILjava_nio_IntBuffer_2 }, +{"glGetTexParameterxv", "(II[II)V", (void *) android_glGetTexParameterxv__II_3II }, +{"glGetTexParameterxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameterxv__IILjava_nio_IntBuffer_2 }, +{"glIsBuffer", "(I)Z", (void *) android_glIsBuffer__I }, +{"glIsEnabled", "(I)Z", (void *) android_glIsEnabled__I }, +{"glIsTexture", "(I)Z", (void *) android_glIsTexture__I }, +{"glNormalPointer", "(III)V", (void *) android_glNormalPointer__III }, +{"glPointParameterf", "(IF)V", (void *) android_glPointParameterf__IF }, +{"glPointParameterfv", "(I[FI)V", (void *) android_glPointParameterfv__I_3FI }, +{"glPointParameterfv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glPointParameterfv__ILjava_nio_FloatBuffer_2 }, +{"glPointParameterx", "(II)V", (void *) android_glPointParameterx__II }, +{"glPointParameterxv", "(I[II)V", (void *) android_glPointParameterxv__I_3II }, +{"glPointParameterxv", "(ILjava/nio/IntBuffer;)V", (void *) android_glPointParameterxv__ILjava_nio_IntBuffer_2 }, +{"glPointSizePointerOES", "(IILjava/nio/Buffer;)V", (void *) android_glPointSizePointerOES__IILjava_nio_Buffer_2 }, +{"glTexCoordPointer", "(IIII)V", (void *) android_glTexCoordPointer__IIII }, +{"glTexEnvi", "(III)V", (void *) android_glTexEnvi__III }, +{"glTexEnviv", "(II[II)V", (void *) android_glTexEnviv__II_3II }, +{"glTexEnviv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexEnviv__IILjava_nio_IntBuffer_2 }, +{"glTexParameterfv", "(II[FI)V", (void *) android_glTexParameterfv__II_3FI }, +{"glTexParameterfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glTexParameterfv__IILjava_nio_FloatBuffer_2 }, +{"glTexParameteri", "(III)V", (void *) android_glTexParameteri__III }, +{"glTexParameteriv", "(II[II)V", (void *) android_glTexParameteriv__II_3II }, +{"glTexParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameteriv__IILjava_nio_IntBuffer_2 }, +{"glTexParameterxv", "(II[II)V", (void *) android_glTexParameterxv__II_3II }, +{"glTexParameterxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameterxv__IILjava_nio_IntBuffer_2 }, +{"glVertexPointer", "(IIII)V", (void *) android_glVertexPointer__IIII }, +}; + +int register_android_opengl_jni_GLES11(JNIEnv *_env) +{ + int err; + err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods)); + return err; +} diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6f3495c5062ceaba6089699daf0203736675bf99 --- /dev/null +++ b/core/jni/android_opengl_GLES11Ext.cpp @@ -0,0 +1,2461 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +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. */ + +static 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); +} + +// -------------------------------------------------------------------------- + +/* void glBlendEquationSeparateOES ( GLenum modeRGB, GLenum modeAlpha ) */ +static void +android_glBlendEquationSeparateOES__II + (JNIEnv *_env, jobject _this, jint modeRGB, jint modeAlpha) { + glBlendEquationSeparateOES( + (GLenum)modeRGB, + (GLenum)modeAlpha + ); +} + +/* void glBlendFuncSeparateOES ( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) */ +static void +android_glBlendFuncSeparateOES__IIII + (JNIEnv *_env, jobject _this, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) { + glBlendFuncSeparateOES( + (GLenum)srcRGB, + (GLenum)dstRGB, + (GLenum)srcAlpha, + (GLenum)dstAlpha + ); +} + +/* void glBlendEquationOES ( GLenum mode ) */ +static void +android_glBlendEquationOES__I + (JNIEnv *_env, jobject _this, jint mode) { + glBlendEquationOES( + (GLenum)mode + ); +} + +/* void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height ) */ +static void +android_glDrawTexsOES__SSSSS + (JNIEnv *_env, jobject _this, jshort x, jshort y, jshort z, jshort width, jshort height) { + glDrawTexsOES( + (GLshort)x, + (GLshort)y, + (GLshort)z, + (GLshort)width, + (GLshort)height + ); +} + +/* void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height ) */ +static void +android_glDrawTexiOES__IIIII + (JNIEnv *_env, jobject _this, jint x, jint y, jint z, jint width, jint height) { + glDrawTexiOES( + (GLint)x, + (GLint)y, + (GLint)z, + (GLint)width, + (GLint)height + ); +} + +/* void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height ) */ +static void +android_glDrawTexxOES__IIIII + (JNIEnv *_env, jobject _this, jint x, jint y, jint z, jint width, jint height) { + glDrawTexxOES( + (GLfixed)x, + (GLfixed)y, + (GLfixed)z, + (GLfixed)width, + (GLfixed)height + ); +} + +/* void glDrawTexsvOES ( const GLshort *coords ) */ +static void +android_glDrawTexsvOES___3SI + (JNIEnv *_env, jobject _this, jshortArray coords_ref, jint offset) { + GLshort *coords_base = (GLshort *) 0; + jint _remaining; + GLshort *coords = (GLshort *) 0; + + if (!coords_ref) { + _env->ThrowNew(IAEClass, "coords == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(coords_ref) - offset; + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "length - offset < 5"); + goto exit; + } + coords_base = (GLshort *) + _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0); + coords = coords_base + offset; + + glDrawTexsvOES( + (GLshort *)coords + ); + +exit: + if (coords_base) { + _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base, + JNI_ABORT); + } +} + +/* void glDrawTexsvOES ( const GLshort *coords ) */ +static void +android_glDrawTexsvOES__Ljava_nio_ShortBuffer_2 + (JNIEnv *_env, jobject _this, jobject coords_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLshort *coords = (GLshort *) 0; + + coords = (GLshort *)getPointer(_env, coords_buf, &_array, &_remaining); + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "remaining() < 5"); + goto exit; + } + glDrawTexsvOES( + (GLshort *)coords + ); + +exit: + if (_array) { + releasePointer(_env, _array, coords, JNI_FALSE); + } +} + +/* void glDrawTexivOES ( const GLint *coords ) */ +static void +android_glDrawTexivOES___3II + (JNIEnv *_env, jobject _this, jintArray coords_ref, jint offset) { + GLint *coords_base = (GLint *) 0; + jint _remaining; + GLint *coords = (GLint *) 0; + + if (!coords_ref) { + _env->ThrowNew(IAEClass, "coords == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(coords_ref) - offset; + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "length - offset < 5"); + goto exit; + } + coords_base = (GLint *) + _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0); + coords = coords_base + offset; + + glDrawTexivOES( + (GLint *)coords + ); + +exit: + if (coords_base) { + _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base, + JNI_ABORT); + } +} + +/* void glDrawTexivOES ( const GLint *coords ) */ +static void +android_glDrawTexivOES__Ljava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jobject coords_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLint *coords = (GLint *) 0; + + coords = (GLint *)getPointer(_env, coords_buf, &_array, &_remaining); + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "remaining() < 5"); + goto exit; + } + glDrawTexivOES( + (GLint *)coords + ); + +exit: + if (_array) { + releasePointer(_env, _array, coords, JNI_FALSE); + } +} + +/* void glDrawTexxvOES ( const GLfixed *coords ) */ +static void +android_glDrawTexxvOES___3II + (JNIEnv *_env, jobject _this, jintArray coords_ref, jint offset) { + GLfixed *coords_base = (GLfixed *) 0; + jint _remaining; + GLfixed *coords = (GLfixed *) 0; + + if (!coords_ref) { + _env->ThrowNew(IAEClass, "coords == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(coords_ref) - offset; + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "length - offset < 5"); + goto exit; + } + coords_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0); + coords = coords_base + offset; + + glDrawTexxvOES( + (GLfixed *)coords + ); + +exit: + if (coords_base) { + _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base, + JNI_ABORT); + } +} + +/* void glDrawTexxvOES ( const GLfixed *coords ) */ +static void +android_glDrawTexxvOES__Ljava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jobject coords_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *coords = (GLfixed *) 0; + + coords = (GLfixed *)getPointer(_env, coords_buf, &_array, &_remaining); + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "remaining() < 5"); + goto exit; + } + glDrawTexxvOES( + (GLfixed *)coords + ); + +exit: + if (_array) { + releasePointer(_env, _array, coords, JNI_FALSE); + } +} + +/* void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height ) */ +static void +android_glDrawTexfOES__FFFFF + (JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z, jfloat width, jfloat height) { + glDrawTexfOES( + (GLfloat)x, + (GLfloat)y, + (GLfloat)z, + (GLfloat)width, + (GLfloat)height + ); +} + +/* void glDrawTexfvOES ( const GLfloat *coords ) */ +static void +android_glDrawTexfvOES___3FI + (JNIEnv *_env, jobject _this, jfloatArray coords_ref, jint offset) { + GLfloat *coords_base = (GLfloat *) 0; + jint _remaining; + GLfloat *coords = (GLfloat *) 0; + + if (!coords_ref) { + _env->ThrowNew(IAEClass, "coords == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(coords_ref) - offset; + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "length - offset < 5"); + goto exit; + } + coords_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0); + coords = coords_base + offset; + + glDrawTexfvOES( + (GLfloat *)coords + ); + +exit: + if (coords_base) { + _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base, + JNI_ABORT); + } +} + +/* void glDrawTexfvOES ( const GLfloat *coords ) */ +static void +android_glDrawTexfvOES__Ljava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jobject coords_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *coords = (GLfloat *) 0; + + coords = (GLfloat *)getPointer(_env, coords_buf, &_array, &_remaining); + if (_remaining < 5) { + _env->ThrowNew(IAEClass, "remaining() < 5"); + goto exit; + } + glDrawTexfvOES( + (GLfloat *)coords + ); + +exit: + if (_array) { + releasePointer(_env, _array, coords, JNI_FALSE); + } +} + +/* void glEGLImageTargetTexture2DOES ( GLenum target, GLeglImageOES image ) */ +static void +android_glEGLImageTargetTexture2DOES__ILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint target, jobject image_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLeglImageOES image = (GLeglImageOES) 0; + + image = (GLeglImageOES)getPointer(_env, image_buf, &_array, &_remaining); + glEGLImageTargetTexture2DOES( + (GLenum)target, + (GLeglImageOES)image + ); + if (_array) { + releasePointer(_env, _array, image, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glEGLImageTargetRenderbufferStorageOES ( GLenum target, GLeglImageOES image ) */ +static void +android_glEGLImageTargetRenderbufferStorageOES__ILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint target, jobject image_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLeglImageOES image = (GLeglImageOES) 0; + + image = (GLeglImageOES)getPointer(_env, image_buf, &_array, &_remaining); + glEGLImageTargetRenderbufferStorageOES( + (GLenum)target, + (GLeglImageOES)image + ); + if (_array) { + releasePointer(_env, _array, image, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glAlphaFuncxOES ( GLenum func, GLclampx ref ) */ +static void +android_glAlphaFuncxOES__II + (JNIEnv *_env, jobject _this, jint func, jint ref) { + glAlphaFuncxOES( + (GLenum)func, + (GLclampx)ref + ); +} + +/* void glClearColorxOES ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) */ +static void +android_glClearColorxOES__IIII + (JNIEnv *_env, jobject _this, jint red, jint green, jint blue, jint alpha) { + glClearColorxOES( + (GLclampx)red, + (GLclampx)green, + (GLclampx)blue, + (GLclampx)alpha + ); +} + +/* void glClearDepthxOES ( GLclampx depth ) */ +static void +android_glClearDepthxOES__I + (JNIEnv *_env, jobject _this, jint depth) { + glClearDepthxOES( + (GLclampx)depth + ); +} + +/* void glClipPlanexOES ( GLenum plane, const GLfixed *equation ) */ +static void +android_glClipPlanexOES__I_3II + (JNIEnv *_env, jobject _this, jint plane, jintArray equation_ref, jint offset) { + GLfixed *equation_base = (GLfixed *) 0; + jint _remaining; + GLfixed *equation = (GLfixed *) 0; + + if (!equation_ref) { + _env->ThrowNew(IAEClass, "equation == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(equation_ref) - offset; + equation_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(equation_ref, (jboolean *)0); + equation = equation_base + offset; + + glClipPlanexOES( + (GLenum)plane, + (GLfixed *)equation + ); + +exit: + if (equation_base) { + _env->ReleasePrimitiveArrayCritical(equation_ref, equation_base, + JNI_ABORT); + } +} + +/* void glClipPlanexOES ( GLenum plane, const GLfixed *equation ) */ +static void +android_glClipPlanexOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *equation = (GLfixed *) 0; + + equation = (GLfixed *)getPointer(_env, equation_buf, &_array, &_remaining); + glClipPlanexOES( + (GLenum)plane, + (GLfixed *)equation + ); + if (_array) { + releasePointer(_env, _array, equation, JNI_FALSE); + } +} + +/* void glColor4xOES ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) */ +static void +android_glColor4xOES__IIII + (JNIEnv *_env, jobject _this, jint red, jint green, jint blue, jint alpha) { + glColor4xOES( + (GLfixed)red, + (GLfixed)green, + (GLfixed)blue, + (GLfixed)alpha + ); +} + +/* void glDepthRangexOES ( GLclampx zNear, GLclampx zFar ) */ +static void +android_glDepthRangexOES__II + (JNIEnv *_env, jobject _this, jint zNear, jint zFar) { + glDepthRangexOES( + (GLclampx)zNear, + (GLclampx)zFar + ); +} + +/* void glFogxOES ( GLenum pname, GLfixed param ) */ +static void +android_glFogxOES__II + (JNIEnv *_env, jobject _this, jint pname, jint param) { + glFogxOES( + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glFogxvOES ( GLenum pname, const GLfixed *params ) */ +static void +android_glFogxvOES__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glFogxvOES( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glFogxvOES ( GLenum pname, const GLfixed *params ) */ +static void +android_glFogxvOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glFogxvOES( + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glFrustumxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) */ +static void +android_glFrustumxOES__IIIIII + (JNIEnv *_env, jobject _this, jint left, jint right, jint bottom, jint top, jint zNear, jint zFar) { + glFrustumxOES( + (GLfixed)left, + (GLfixed)right, + (GLfixed)bottom, + (GLfixed)top, + (GLfixed)zNear, + (GLfixed)zFar + ); +} + +/* void glGetClipPlanexOES ( GLenum pname, GLfixed *eqn ) */ +static void +android_glGetClipPlanexOES__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray eqn_ref, jint offset) { + jint _exception = 0; + GLfixed *eqn_base = (GLfixed *) 0; + jint _remaining; + GLfixed *eqn = (GLfixed *) 0; + + if (!eqn_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "eqn == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(eqn_ref) - offset; + if (_remaining < 4) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < 4"); + goto exit; + } + eqn_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(eqn_ref, (jboolean *)0); + eqn = eqn_base + offset; + + glGetClipPlanexOES( + (GLenum)pname, + (GLfixed *)eqn + ); + +exit: + if (eqn_base) { + _env->ReleasePrimitiveArrayCritical(eqn_ref, eqn_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetClipPlanexOES ( GLenum pname, GLfixed *eqn ) */ +static void +android_glGetClipPlanexOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *eqn = (GLfixed *) 0; + + eqn = (GLfixed *)getPointer(_env, eqn_buf, &_array, &_remaining); + if (_remaining < 4) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < 4"); + goto exit; + } + glGetClipPlanexOES( + (GLenum)pname, + (GLfixed *)eqn + ); + +exit: + if (_array) { + releasePointer(_env, _array, eqn, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetFixedvOES ( GLenum pname, GLfixed *params ) */ +static void +android_glGetFixedvOES__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetFixedvOES( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetFixedvOES ( GLenum pname, GLfixed *params ) */ +static void +android_glGetFixedvOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glGetFixedvOES( + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetLightxvOES ( GLenum light, GLenum pname, GLfixed *params ) */ +static void +android_glGetLightxvOES__II_3II + (JNIEnv *_env, jobject _this, jint light, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetLightxvOES( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetLightxvOES ( GLenum light, GLenum pname, GLfixed *params ) */ +static void +android_glGetLightxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glGetLightxvOES( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetMaterialxvOES ( GLenum face, GLenum pname, GLfixed *params ) */ +static void +android_glGetMaterialxvOES__II_3II + (JNIEnv *_env, jobject _this, jint face, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetMaterialxvOES( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetMaterialxvOES ( GLenum face, GLenum pname, GLfixed *params ) */ +static void +android_glGetMaterialxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glGetMaterialxvOES( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexEnvxvOES ( GLenum env, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexEnvxvOES__II_3II + (JNIEnv *_env, jobject _this, jint env, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexEnvxvOES( + (GLenum)env, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexEnvxvOES ( GLenum env, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexEnvxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint env, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexEnvxvOES( + (GLenum)env, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexParameterxvOES ( GLenum target, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexParameterxvOES__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexParameterxvOES( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexParameterxvOES ( GLenum target, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexParameterxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexParameterxvOES( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glLightModelxOES ( GLenum pname, GLfixed param ) */ +static void +android_glLightModelxOES__II + (JNIEnv *_env, jobject _this, jint pname, jint param) { + glLightModelxOES( + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glLightModelxvOES ( GLenum pname, const GLfixed *params ) */ +static void +android_glLightModelxvOES__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glLightModelxvOES( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glLightModelxvOES ( GLenum pname, const GLfixed *params ) */ +static void +android_glLightModelxvOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glLightModelxvOES( + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glLightxOES ( GLenum light, GLenum pname, GLfixed param ) */ +static void +android_glLightxOES__III + (JNIEnv *_env, jobject _this, jint light, jint pname, jint param) { + glLightxOES( + (GLenum)light, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glLightxvOES ( GLenum light, GLenum pname, const GLfixed *params ) */ +static void +android_glLightxvOES__II_3II + (JNIEnv *_env, jobject _this, jint light, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glLightxvOES( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glLightxvOES ( GLenum light, GLenum pname, const GLfixed *params ) */ +static void +android_glLightxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glLightxvOES( + (GLenum)light, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glLineWidthxOES ( GLfixed width ) */ +static void +android_glLineWidthxOES__I + (JNIEnv *_env, jobject _this, jint width) { + glLineWidthxOES( + (GLfixed)width + ); +} + +/* void glLoadMatrixxOES ( const GLfixed *m ) */ +static void +android_glLoadMatrixxOES___3II + (JNIEnv *_env, jobject _this, jintArray m_ref, jint offset) { + GLfixed *m_base = (GLfixed *) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + if (!m_ref) { + _env->ThrowNew(IAEClass, "m == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(m_ref) - offset; + m_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0); + m = m_base + offset; + + glLoadMatrixxOES( + (GLfixed *)m + ); + +exit: + if (m_base) { + _env->ReleasePrimitiveArrayCritical(m_ref, m_base, + JNI_ABORT); + } +} + +/* void glLoadMatrixxOES ( const GLfixed *m ) */ +static void +android_glLoadMatrixxOES__Ljava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jobject m_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + m = (GLfixed *)getPointer(_env, m_buf, &_array, &_remaining); + glLoadMatrixxOES( + (GLfixed *)m + ); + if (_array) { + releasePointer(_env, _array, m, JNI_FALSE); + } +} + +/* void glMaterialxOES ( GLenum face, GLenum pname, GLfixed param ) */ +static void +android_glMaterialxOES__III + (JNIEnv *_env, jobject _this, jint face, jint pname, jint param) { + glMaterialxOES( + (GLenum)face, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glMaterialxvOES ( GLenum face, GLenum pname, const GLfixed *params ) */ +static void +android_glMaterialxvOES__II_3II + (JNIEnv *_env, jobject _this, jint face, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glMaterialxvOES( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glMaterialxvOES ( GLenum face, GLenum pname, const GLfixed *params ) */ +static void +android_glMaterialxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glMaterialxvOES( + (GLenum)face, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glMultMatrixxOES ( const GLfixed *m ) */ +static void +android_glMultMatrixxOES___3II + (JNIEnv *_env, jobject _this, jintArray m_ref, jint offset) { + GLfixed *m_base = (GLfixed *) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + if (!m_ref) { + _env->ThrowNew(IAEClass, "m == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(m_ref) - offset; + m_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0); + m = m_base + offset; + + glMultMatrixxOES( + (GLfixed *)m + ); + +exit: + if (m_base) { + _env->ReleasePrimitiveArrayCritical(m_ref, m_base, + JNI_ABORT); + } +} + +/* void glMultMatrixxOES ( const GLfixed *m ) */ +static void +android_glMultMatrixxOES__Ljava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jobject m_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *m = (GLfixed *) 0; + + m = (GLfixed *)getPointer(_env, m_buf, &_array, &_remaining); + glMultMatrixxOES( + (GLfixed *)m + ); + if (_array) { + releasePointer(_env, _array, m, JNI_FALSE); + } +} + +/* void glMultiTexCoord4xOES ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) */ +static void +android_glMultiTexCoord4xOES__IIIII + (JNIEnv *_env, jobject _this, jint target, jint s, jint t, jint r, jint q) { + glMultiTexCoord4xOES( + (GLenum)target, + (GLfixed)s, + (GLfixed)t, + (GLfixed)r, + (GLfixed)q + ); +} + +/* void glNormal3xOES ( GLfixed nx, GLfixed ny, GLfixed nz ) */ +static void +android_glNormal3xOES__III + (JNIEnv *_env, jobject _this, jint nx, jint ny, jint nz) { + glNormal3xOES( + (GLfixed)nx, + (GLfixed)ny, + (GLfixed)nz + ); +} + +/* void glOrthoxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) */ +static void +android_glOrthoxOES__IIIIII + (JNIEnv *_env, jobject _this, jint left, jint right, jint bottom, jint top, jint zNear, jint zFar) { + glOrthoxOES( + (GLfixed)left, + (GLfixed)right, + (GLfixed)bottom, + (GLfixed)top, + (GLfixed)zNear, + (GLfixed)zFar + ); +} + +/* void glPointParameterxOES ( GLenum pname, GLfixed param ) */ +static void +android_glPointParameterxOES__II + (JNIEnv *_env, jobject _this, jint pname, jint param) { + glPointParameterxOES( + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glPointParameterxvOES ( GLenum pname, const GLfixed *params ) */ +static void +android_glPointParameterxvOES__I_3II + (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glPointParameterxvOES( + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glPointParameterxvOES ( GLenum pname, const GLfixed *params ) */ +static void +android_glPointParameterxvOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glPointParameterxvOES( + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glPointSizexOES ( GLfixed size ) */ +static void +android_glPointSizexOES__I + (JNIEnv *_env, jobject _this, jint size) { + glPointSizexOES( + (GLfixed)size + ); +} + +/* void glPolygonOffsetxOES ( GLfixed factor, GLfixed units ) */ +static void +android_glPolygonOffsetxOES__II + (JNIEnv *_env, jobject _this, jint factor, jint units) { + glPolygonOffsetxOES( + (GLfixed)factor, + (GLfixed)units + ); +} + +/* void glRotatexOES ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) */ +static void +android_glRotatexOES__IIII + (JNIEnv *_env, jobject _this, jint angle, jint x, jint y, jint z) { + glRotatexOES( + (GLfixed)angle, + (GLfixed)x, + (GLfixed)y, + (GLfixed)z + ); +} + +/* void glSampleCoveragexOES ( GLclampx value, GLboolean invert ) */ +static void +android_glSampleCoveragexOES__IZ + (JNIEnv *_env, jobject _this, jint value, jboolean invert) { + glSampleCoveragexOES( + (GLclampx)value, + (GLboolean)invert + ); +} + +/* void glScalexOES ( GLfixed x, GLfixed y, GLfixed z ) */ +static void +android_glScalexOES__III + (JNIEnv *_env, jobject _this, jint x, jint y, jint z) { + glScalexOES( + (GLfixed)x, + (GLfixed)y, + (GLfixed)z + ); +} + +/* void glTexEnvxOES ( GLenum target, GLenum pname, GLfixed param ) */ +static void +android_glTexEnvxOES__III + (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) { + glTexEnvxOES( + (GLenum)target, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glTexEnvxvOES ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexEnvxvOES__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexEnvxvOES( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexEnvxvOES ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexEnvxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glTexEnvxvOES( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexParameterxOES ( GLenum target, GLenum pname, GLfixed param ) */ +static void +android_glTexParameterxOES__III + (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) { + glTexParameterxOES( + (GLenum)target, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glTexParameterxvOES ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexParameterxvOES__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexParameterxvOES( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexParameterxvOES ( GLenum target, GLenum pname, const GLfixed *params ) */ +static void +android_glTexParameterxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glTexParameterxvOES( + (GLenum)target, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTranslatexOES ( GLfixed x, GLfixed y, GLfixed z ) */ +static void +android_glTranslatexOES__III + (JNIEnv *_env, jobject _this, jint x, jint y, jint z) { + glTranslatexOES( + (GLfixed)x, + (GLfixed)y, + (GLfixed)z + ); +} + +/* GLboolean glIsRenderbufferOES ( GLuint renderbuffer ) */ +static jboolean +android_glIsRenderbufferOES__I + (JNIEnv *_env, jobject _this, jint renderbuffer) { + _env->ThrowNew(UOEClass, + "glIsRenderbufferOES"); + return JNI_FALSE; +} + +/* void glBindRenderbufferOES ( GLenum target, GLuint renderbuffer ) */ +static void +android_glBindRenderbufferOES__II + (JNIEnv *_env, jobject _this, jint target, jint renderbuffer) { + _env->ThrowNew(UOEClass, + "glBindRenderbufferOES"); +} + +/* void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) */ +static void +android_glDeleteRenderbuffersOES__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) { + _env->ThrowNew(UOEClass, + "glDeleteRenderbuffersOES"); +} + +/* void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) */ +static void +android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) { + _env->ThrowNew(UOEClass, + "glDeleteRenderbuffersOES"); +} + +/* void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) */ +static void +android_glGenRenderbuffersOES__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) { + _env->ThrowNew(UOEClass, + "glGenRenderbuffersOES"); +} + +/* void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) */ +static void +android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) { + _env->ThrowNew(UOEClass, + "glGenRenderbuffersOES"); +} + +/* void glRenderbufferStorageOES ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) */ +static void +android_glRenderbufferStorageOES__IIII + (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint width, jint height) { + _env->ThrowNew(UOEClass, + "glRenderbufferStorageOES"); +} + +/* void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) */ +static void +android_glGetRenderbufferParameterivOES__II_3II + (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { + _env->ThrowNew(UOEClass, + "glGetRenderbufferParameterivOES"); +} + +/* void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) */ +static void +android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { + _env->ThrowNew(UOEClass, + "glGetRenderbufferParameterivOES"); +} + +/* GLboolean glIsFramebufferOES ( GLuint framebuffer ) */ +static jboolean +android_glIsFramebufferOES__I + (JNIEnv *_env, jobject _this, jint framebuffer) { + _env->ThrowNew(UOEClass, + "glIsFramebufferOES"); + return JNI_FALSE; +} + +/* void glBindFramebufferOES ( GLenum target, GLuint framebuffer ) */ +static void +android_glBindFramebufferOES__II + (JNIEnv *_env, jobject _this, jint target, jint framebuffer) { + _env->ThrowNew(UOEClass, + "glBindFramebufferOES"); +} + +/* void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) */ +static void +android_glDeleteFramebuffersOES__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) { + _env->ThrowNew(UOEClass, + "glDeleteFramebuffersOES"); +} + +/* void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) */ +static void +android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) { + _env->ThrowNew(UOEClass, + "glDeleteFramebuffersOES"); +} + +/* void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) */ +static void +android_glGenFramebuffersOES__I_3II + (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) { + _env->ThrowNew(UOEClass, + "glGenFramebuffersOES"); +} + +/* void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) */ +static void +android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) { + _env->ThrowNew(UOEClass, + "glGenFramebuffersOES"); +} + +/* GLenum glCheckFramebufferStatusOES ( GLenum target ) */ +static jint +android_glCheckFramebufferStatusOES__I + (JNIEnv *_env, jobject _this, jint target) { + _env->ThrowNew(UOEClass, + "glCheckFramebufferStatusOES"); + return 0; +} + +/* void glFramebufferRenderbufferOES ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) */ +static void +android_glFramebufferRenderbufferOES__IIII + (JNIEnv *_env, jobject _this, jint target, jint attachment, jint renderbuffertarget, jint renderbuffer) { + _env->ThrowNew(UOEClass, + "glFramebufferRenderbufferOES"); +} + +/* void glFramebufferTexture2DOES ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) */ +static void +android_glFramebufferTexture2DOES__IIIII + (JNIEnv *_env, jobject _this, jint target, jint attachment, jint textarget, jint texture, jint level) { + _env->ThrowNew(UOEClass, + "glFramebufferTexture2DOES"); +} + +/* void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) */ +static void +android_glGetFramebufferAttachmentParameterivOES__III_3II + (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jintArray params_ref, jint offset) { + _env->ThrowNew(UOEClass, + "glGetFramebufferAttachmentParameterivOES"); +} + +/* void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) */ +static void +android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jobject params_buf) { + _env->ThrowNew(UOEClass, + "glGetFramebufferAttachmentParameterivOES"); +} + +/* void glGenerateMipmapOES ( GLenum target ) */ +static void +android_glGenerateMipmapOES__I + (JNIEnv *_env, jobject _this, jint target) { + _env->ThrowNew(UOEClass, + "glGenerateMipmapOES"); +} + +/* void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) */ +static void +android_glCurrentPaletteMatrixOES__I + (JNIEnv *_env, jobject _this, jint matrixpaletteindex) { + _env->ThrowNew(UOEClass, + "glCurrentPaletteMatrixOES"); +} + +/* void glLoadPaletteFromModelViewMatrixOES ( void ) */ +static void +android_glLoadPaletteFromModelViewMatrixOES__ + (JNIEnv *_env, jobject _this) { + _env->ThrowNew(UOEClass, + "glLoadPaletteFromModelViewMatrixOES"); +} + +/* void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */ +static void +android_glMatrixIndexPointerOES__IIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf) { + _env->ThrowNew(UOEClass, + "glMatrixIndexPointerOES"); +} + +/* void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */ +static void +android_glWeightPointerOES__IIILjava_nio_Buffer_2 + (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf) { + _env->ThrowNew(UOEClass, + "glWeightPointerOES"); +} + +/* void glDepthRangefOES ( GLclampf zNear, GLclampf zFar ) */ +static void +android_glDepthRangefOES__FF + (JNIEnv *_env, jobject _this, jfloat zNear, jfloat zFar) { + glDepthRangefOES( + (GLclampf)zNear, + (GLclampf)zFar + ); +} + +/* void glFrustumfOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */ +static void +android_glFrustumfOES__FFFFFF + (JNIEnv *_env, jobject _this, jfloat left, jfloat right, jfloat bottom, jfloat top, jfloat zNear, jfloat zFar) { + glFrustumfOES( + (GLfloat)left, + (GLfloat)right, + (GLfloat)bottom, + (GLfloat)top, + (GLfloat)zNear, + (GLfloat)zFar + ); +} + +/* void glOrthofOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */ +static void +android_glOrthofOES__FFFFFF + (JNIEnv *_env, jobject _this, jfloat left, jfloat right, jfloat bottom, jfloat top, jfloat zNear, jfloat zFar) { + glOrthofOES( + (GLfloat)left, + (GLfloat)right, + (GLfloat)bottom, + (GLfloat)top, + (GLfloat)zNear, + (GLfloat)zFar + ); +} + +/* void glClipPlanefOES ( GLenum plane, const GLfloat *equation ) */ +static void +android_glClipPlanefOES__I_3FI + (JNIEnv *_env, jobject _this, jint plane, jfloatArray equation_ref, jint offset) { + GLfloat *equation_base = (GLfloat *) 0; + jint _remaining; + GLfloat *equation = (GLfloat *) 0; + + if (!equation_ref) { + _env->ThrowNew(IAEClass, "equation == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(equation_ref) - offset; + equation_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(equation_ref, (jboolean *)0); + equation = equation_base + offset; + + glClipPlanefOES( + (GLenum)plane, + (GLfloat *)equation + ); + +exit: + if (equation_base) { + _env->ReleasePrimitiveArrayCritical(equation_ref, equation_base, + JNI_ABORT); + } +} + +/* void glClipPlanefOES ( GLenum plane, const GLfloat *equation ) */ +static void +android_glClipPlanefOES__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *equation = (GLfloat *) 0; + + equation = (GLfloat *)getPointer(_env, equation_buf, &_array, &_remaining); + glClipPlanefOES( + (GLenum)plane, + (GLfloat *)equation + ); + if (_array) { + releasePointer(_env, _array, equation, JNI_FALSE); + } +} + +/* void glGetClipPlanefOES ( GLenum pname, GLfloat *eqn ) */ +static void +android_glGetClipPlanefOES__I_3FI + (JNIEnv *_env, jobject _this, jint pname, jfloatArray eqn_ref, jint offset) { + jint _exception = 0; + GLfloat *eqn_base = (GLfloat *) 0; + jint _remaining; + GLfloat *eqn = (GLfloat *) 0; + + if (!eqn_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "eqn == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(eqn_ref) - offset; + if (_remaining < 4) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < 4"); + goto exit; + } + eqn_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(eqn_ref, (jboolean *)0); + eqn = eqn_base + offset; + + glGetClipPlanefOES( + (GLenum)pname, + (GLfloat *)eqn + ); + +exit: + if (eqn_base) { + _env->ReleasePrimitiveArrayCritical(eqn_ref, eqn_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetClipPlanefOES ( GLenum pname, GLfloat *eqn ) */ +static void +android_glGetClipPlanefOES__ILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *eqn = (GLfloat *) 0; + + eqn = (GLfloat *)getPointer(_env, eqn_buf, &_array, &_remaining); + if (_remaining < 4) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < 4"); + goto exit; + } + glGetClipPlanefOES( + (GLenum)pname, + (GLfloat *)eqn + ); + +exit: + if (_array) { + releasePointer(_env, _array, eqn, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glClearDepthfOES ( GLclampf depth ) */ +static void +android_glClearDepthfOES__F + (JNIEnv *_env, jobject _this, jfloat depth) { + glClearDepthfOES( + (GLclampf)depth + ); +} + +/* void glTexGenfOES ( GLenum coord, GLenum pname, GLfloat param ) */ +static void +android_glTexGenfOES__IIF + (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloat param) { + glTexGenfOES( + (GLenum)coord, + (GLenum)pname, + (GLfloat)param + ); +} + +/* void glTexGenfvOES ( GLenum coord, GLenum pname, const GLfloat *params ) */ +static void +android_glTexGenfvOES__II_3FI + (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) { + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexGenfvOES( + (GLenum)coord, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexGenfvOES ( GLenum coord, GLenum pname, const GLfloat *params ) */ +static void +android_glTexGenfvOES__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + glTexGenfvOES( + (GLenum)coord, + (GLenum)pname, + (GLfloat *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexGeniOES ( GLenum coord, GLenum pname, GLint param ) */ +static void +android_glTexGeniOES__III + (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) { + glTexGeniOES( + (GLenum)coord, + (GLenum)pname, + (GLint)param + ); +} + +/* void glTexGenivOES ( GLenum coord, GLenum pname, const GLint *params ) */ +static void +android_glTexGenivOES__II_3II + (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexGenivOES( + (GLenum)coord, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexGenivOES ( GLenum coord, GLenum pname, const GLint *params ) */ +static void +android_glTexGenivOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glTexGenivOES( + (GLenum)coord, + (GLenum)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glTexGenxOES ( GLenum coord, GLenum pname, GLfixed param ) */ +static void +android_glTexGenxOES__III + (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) { + glTexGenxOES( + (GLenum)coord, + (GLenum)pname, + (GLfixed)param + ); +} + +/* void glTexGenxvOES ( GLenum coord, GLenum pname, const GLfixed *params ) */ +static void +android_glTexGenxvOES__II_3II + (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexGenxvOES( + (GLenum)coord, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + JNI_ABORT); + } +} + +/* void glTexGenxvOES ( GLenum coord, GLenum pname, const GLfixed *params ) */ +static void +android_glTexGenxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glTexGenxvOES( + (GLenum)coord, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, JNI_FALSE); + } +} + +/* void glGetTexGenfvOES ( GLenum coord, GLenum pname, GLfloat *params ) */ +static void +android_glGetTexGenfvOES__II_3FI + (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) { + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexGenfvOES( + (GLenum)coord, + (GLenum)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexGenfvOES ( GLenum coord, GLenum pname, GLfloat *params ) */ +static void +android_glGetTexGenfvOES__IILjava_nio_FloatBuffer_2 + (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexGenfvOES( + (GLenum)coord, + (GLenum)pname, + (GLfloat *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexGenivOES ( GLenum coord, GLenum pname, GLint *params ) */ +static void +android_glGetTexGenivOES__II_3II + (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexGenivOES( + (GLenum)coord, + (GLenum)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexGenivOES ( GLenum coord, GLenum pname, GLint *params ) */ +static void +android_glGetTexGenivOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexGenivOES( + (GLenum)coord, + (GLenum)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +/* void glGetTexGenxvOES ( GLenum coord, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexGenxvOES__II_3II + (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { + jint _exception = 0; + GLfixed *params_base = (GLfixed *) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfixed *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexGenxvOES( + (GLenum)coord, + (GLenum)pname, + (GLfixed *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } +} + +/* void glGetTexGenxvOES ( GLenum coord, GLenum pname, GLfixed *params ) */ +static void +android_glGetTexGenxvOES__IILjava_nio_IntBuffer_2 + (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfixed *params = (GLfixed *) 0; + + params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexGenxvOES( + (GLenum)coord, + (GLenum)pname, + (GLfixed *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } +} + +static const char *classPathName = "android/opengl/GLES11Ext"; + +static JNINativeMethod methods[] = { +{"_nativeClassInit", "()V", (void*)nativeClassInit }, +{"glBlendEquationSeparateOES", "(II)V", (void *) android_glBlendEquationSeparateOES__II }, +{"glBlendFuncSeparateOES", "(IIII)V", (void *) android_glBlendFuncSeparateOES__IIII }, +{"glBlendEquationOES", "(I)V", (void *) android_glBlendEquationOES__I }, +{"glDrawTexsOES", "(SSSSS)V", (void *) android_glDrawTexsOES__SSSSS }, +{"glDrawTexiOES", "(IIIII)V", (void *) android_glDrawTexiOES__IIIII }, +{"glDrawTexxOES", "(IIIII)V", (void *) android_glDrawTexxOES__IIIII }, +{"glDrawTexsvOES", "([SI)V", (void *) android_glDrawTexsvOES___3SI }, +{"glDrawTexsvOES", "(Ljava/nio/ShortBuffer;)V", (void *) android_glDrawTexsvOES__Ljava_nio_ShortBuffer_2 }, +{"glDrawTexivOES", "([II)V", (void *) android_glDrawTexivOES___3II }, +{"glDrawTexivOES", "(Ljava/nio/IntBuffer;)V", (void *) android_glDrawTexivOES__Ljava_nio_IntBuffer_2 }, +{"glDrawTexxvOES", "([II)V", (void *) android_glDrawTexxvOES___3II }, +{"glDrawTexxvOES", "(Ljava/nio/IntBuffer;)V", (void *) android_glDrawTexxvOES__Ljava_nio_IntBuffer_2 }, +{"glDrawTexfOES", "(FFFFF)V", (void *) android_glDrawTexfOES__FFFFF }, +{"glDrawTexfvOES", "([FI)V", (void *) android_glDrawTexfvOES___3FI }, +{"glDrawTexfvOES", "(Ljava/nio/FloatBuffer;)V", (void *) android_glDrawTexfvOES__Ljava_nio_FloatBuffer_2 }, +{"glEGLImageTargetTexture2DOES", "(ILjava/nio/Buffer;)V", (void *) android_glEGLImageTargetTexture2DOES__ILjava_nio_Buffer_2 }, +{"glEGLImageTargetRenderbufferStorageOES", "(ILjava/nio/Buffer;)V", (void *) android_glEGLImageTargetRenderbufferStorageOES__ILjava_nio_Buffer_2 }, +{"glAlphaFuncxOES", "(II)V", (void *) android_glAlphaFuncxOES__II }, +{"glClearColorxOES", "(IIII)V", (void *) android_glClearColorxOES__IIII }, +{"glClearDepthxOES", "(I)V", (void *) android_glClearDepthxOES__I }, +{"glClipPlanexOES", "(I[II)V", (void *) android_glClipPlanexOES__I_3II }, +{"glClipPlanexOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glClipPlanexOES__ILjava_nio_IntBuffer_2 }, +{"glColor4xOES", "(IIII)V", (void *) android_glColor4xOES__IIII }, +{"glDepthRangexOES", "(II)V", (void *) android_glDepthRangexOES__II }, +{"glFogxOES", "(II)V", (void *) android_glFogxOES__II }, +{"glFogxvOES", "(I[II)V", (void *) android_glFogxvOES__I_3II }, +{"glFogxvOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glFogxvOES__ILjava_nio_IntBuffer_2 }, +{"glFrustumxOES", "(IIIIII)V", (void *) android_glFrustumxOES__IIIIII }, +{"glGetClipPlanexOES", "(I[II)V", (void *) android_glGetClipPlanexOES__I_3II }, +{"glGetClipPlanexOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetClipPlanexOES__ILjava_nio_IntBuffer_2 }, +{"glGetFixedvOES", "(I[II)V", (void *) android_glGetFixedvOES__I_3II }, +{"glGetFixedvOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetFixedvOES__ILjava_nio_IntBuffer_2 }, +{"glGetLightxvOES", "(II[II)V", (void *) android_glGetLightxvOES__II_3II }, +{"glGetLightxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetLightxvOES__IILjava_nio_IntBuffer_2 }, +{"glGetMaterialxvOES", "(II[II)V", (void *) android_glGetMaterialxvOES__II_3II }, +{"glGetMaterialxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetMaterialxvOES__IILjava_nio_IntBuffer_2 }, +{"glGetTexEnvxvOES", "(II[II)V", (void *) android_glGetTexEnvxvOES__II_3II }, +{"glGetTexEnvxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexEnvxvOES__IILjava_nio_IntBuffer_2 }, +{"glGetTexParameterxvOES", "(II[II)V", (void *) android_glGetTexParameterxvOES__II_3II }, +{"glGetTexParameterxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameterxvOES__IILjava_nio_IntBuffer_2 }, +{"glLightModelxOES", "(II)V", (void *) android_glLightModelxOES__II }, +{"glLightModelxvOES", "(I[II)V", (void *) android_glLightModelxvOES__I_3II }, +{"glLightModelxvOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glLightModelxvOES__ILjava_nio_IntBuffer_2 }, +{"glLightxOES", "(III)V", (void *) android_glLightxOES__III }, +{"glLightxvOES", "(II[II)V", (void *) android_glLightxvOES__II_3II }, +{"glLightxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glLightxvOES__IILjava_nio_IntBuffer_2 }, +{"glLineWidthxOES", "(I)V", (void *) android_glLineWidthxOES__I }, +{"glLoadMatrixxOES", "([II)V", (void *) android_glLoadMatrixxOES___3II }, +{"glLoadMatrixxOES", "(Ljava/nio/IntBuffer;)V", (void *) android_glLoadMatrixxOES__Ljava_nio_IntBuffer_2 }, +{"glMaterialxOES", "(III)V", (void *) android_glMaterialxOES__III }, +{"glMaterialxvOES", "(II[II)V", (void *) android_glMaterialxvOES__II_3II }, +{"glMaterialxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glMaterialxvOES__IILjava_nio_IntBuffer_2 }, +{"glMultMatrixxOES", "([II)V", (void *) android_glMultMatrixxOES___3II }, +{"glMultMatrixxOES", "(Ljava/nio/IntBuffer;)V", (void *) android_glMultMatrixxOES__Ljava_nio_IntBuffer_2 }, +{"glMultiTexCoord4xOES", "(IIIII)V", (void *) android_glMultiTexCoord4xOES__IIIII }, +{"glNormal3xOES", "(III)V", (void *) android_glNormal3xOES__III }, +{"glOrthoxOES", "(IIIIII)V", (void *) android_glOrthoxOES__IIIIII }, +{"glPointParameterxOES", "(II)V", (void *) android_glPointParameterxOES__II }, +{"glPointParameterxvOES", "(I[II)V", (void *) android_glPointParameterxvOES__I_3II }, +{"glPointParameterxvOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glPointParameterxvOES__ILjava_nio_IntBuffer_2 }, +{"glPointSizexOES", "(I)V", (void *) android_glPointSizexOES__I }, +{"glPolygonOffsetxOES", "(II)V", (void *) android_glPolygonOffsetxOES__II }, +{"glRotatexOES", "(IIII)V", (void *) android_glRotatexOES__IIII }, +{"glSampleCoveragexOES", "(IZ)V", (void *) android_glSampleCoveragexOES__IZ }, +{"glScalexOES", "(III)V", (void *) android_glScalexOES__III }, +{"glTexEnvxOES", "(III)V", (void *) android_glTexEnvxOES__III }, +{"glTexEnvxvOES", "(II[II)V", (void *) android_glTexEnvxvOES__II_3II }, +{"glTexEnvxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexEnvxvOES__IILjava_nio_IntBuffer_2 }, +{"glTexParameterxOES", "(III)V", (void *) android_glTexParameterxOES__III }, +{"glTexParameterxvOES", "(II[II)V", (void *) android_glTexParameterxvOES__II_3II }, +{"glTexParameterxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameterxvOES__IILjava_nio_IntBuffer_2 }, +{"glTranslatexOES", "(III)V", (void *) android_glTranslatexOES__III }, +{"glIsRenderbufferOES", "(I)Z", (void *) android_glIsRenderbufferOES__I }, +{"glBindRenderbufferOES", "(II)V", (void *) android_glBindRenderbufferOES__II }, +{"glDeleteRenderbuffersOES", "(I[II)V", (void *) android_glDeleteRenderbuffersOES__I_3II }, +{"glDeleteRenderbuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2 }, +{"glGenRenderbuffersOES", "(I[II)V", (void *) android_glGenRenderbuffersOES__I_3II }, +{"glGenRenderbuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2 }, +{"glRenderbufferStorageOES", "(IIII)V", (void *) android_glRenderbufferStorageOES__IIII }, +{"glGetRenderbufferParameterivOES", "(II[II)V", (void *) android_glGetRenderbufferParameterivOES__II_3II }, +{"glGetRenderbufferParameterivOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2 }, +{"glIsFramebufferOES", "(I)Z", (void *) android_glIsFramebufferOES__I }, +{"glBindFramebufferOES", "(II)V", (void *) android_glBindFramebufferOES__II }, +{"glDeleteFramebuffersOES", "(I[II)V", (void *) android_glDeleteFramebuffersOES__I_3II }, +{"glDeleteFramebuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2 }, +{"glGenFramebuffersOES", "(I[II)V", (void *) android_glGenFramebuffersOES__I_3II }, +{"glGenFramebuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2 }, +{"glCheckFramebufferStatusOES", "(I)I", (void *) android_glCheckFramebufferStatusOES__I }, +{"glFramebufferRenderbufferOES", "(IIII)V", (void *) android_glFramebufferRenderbufferOES__IIII }, +{"glFramebufferTexture2DOES", "(IIIII)V", (void *) android_glFramebufferTexture2DOES__IIIII }, +{"glGetFramebufferAttachmentParameterivOES", "(III[II)V", (void *) android_glGetFramebufferAttachmentParameterivOES__III_3II }, +{"glGetFramebufferAttachmentParameterivOES", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2 }, +{"glGenerateMipmapOES", "(I)V", (void *) android_glGenerateMipmapOES__I }, +{"glCurrentPaletteMatrixOES", "(I)V", (void *) android_glCurrentPaletteMatrixOES__I }, +{"glLoadPaletteFromModelViewMatrixOES", "()V", (void *) android_glLoadPaletteFromModelViewMatrixOES__ }, +{"glMatrixIndexPointerOES", "(IIILjava/nio/Buffer;)V", (void *) android_glMatrixIndexPointerOES__IIILjava_nio_Buffer_2 }, +{"glWeightPointerOES", "(IIILjava/nio/Buffer;)V", (void *) android_glWeightPointerOES__IIILjava_nio_Buffer_2 }, +{"glDepthRangefOES", "(FF)V", (void *) android_glDepthRangefOES__FF }, +{"glFrustumfOES", "(FFFFFF)V", (void *) android_glFrustumfOES__FFFFFF }, +{"glOrthofOES", "(FFFFFF)V", (void *) android_glOrthofOES__FFFFFF }, +{"glClipPlanefOES", "(I[FI)V", (void *) android_glClipPlanefOES__I_3FI }, +{"glClipPlanefOES", "(ILjava/nio/FloatBuffer;)V", (void *) android_glClipPlanefOES__ILjava_nio_FloatBuffer_2 }, +{"glGetClipPlanefOES", "(I[FI)V", (void *) android_glGetClipPlanefOES__I_3FI }, +{"glGetClipPlanefOES", "(ILjava/nio/FloatBuffer;)V", (void *) android_glGetClipPlanefOES__ILjava_nio_FloatBuffer_2 }, +{"glClearDepthfOES", "(F)V", (void *) android_glClearDepthfOES__F }, +{"glTexGenfOES", "(IIF)V", (void *) android_glTexGenfOES__IIF }, +{"glTexGenfvOES", "(II[FI)V", (void *) android_glTexGenfvOES__II_3FI }, +{"glTexGenfvOES", "(IILjava/nio/FloatBuffer;)V", (void *) android_glTexGenfvOES__IILjava_nio_FloatBuffer_2 }, +{"glTexGeniOES", "(III)V", (void *) android_glTexGeniOES__III }, +{"glTexGenivOES", "(II[II)V", (void *) android_glTexGenivOES__II_3II }, +{"glTexGenivOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexGenivOES__IILjava_nio_IntBuffer_2 }, +{"glTexGenxOES", "(III)V", (void *) android_glTexGenxOES__III }, +{"glTexGenxvOES", "(II[II)V", (void *) android_glTexGenxvOES__II_3II }, +{"glTexGenxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexGenxvOES__IILjava_nio_IntBuffer_2 }, +{"glGetTexGenfvOES", "(II[FI)V", (void *) android_glGetTexGenfvOES__II_3FI }, +{"glGetTexGenfvOES", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetTexGenfvOES__IILjava_nio_FloatBuffer_2 }, +{"glGetTexGenivOES", "(II[II)V", (void *) android_glGetTexGenivOES__II_3II }, +{"glGetTexGenivOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexGenivOES__IILjava_nio_IntBuffer_2 }, +{"glGetTexGenxvOES", "(II[II)V", (void *) android_glGetTexGenxvOES__II_3II }, +{"glGetTexGenxvOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexGenxvOES__IILjava_nio_IntBuffer_2 }, +}; + +int register_android_opengl_jni_GLES11Ext(JNIEnv *_env) +{ + int err; + err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods)); + return err; +} diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp index 971f87c2969cb0e64945261fe923d6ffcda4265e..848a57adea4d0342ebfeb0ceaf8177ea239ae6db 100644 --- a/core/jni/android_os_ParcelFileDescriptor.cpp +++ b/core/jni/android_os_ParcelFileDescriptor.cpp @@ -1,19 +1,18 @@ -/* //device/libs/android_runtime/android_os_ParcelFileDescriptor.cpp -** -** 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. -*/ +/* + * 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 diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp index 062f8933b23acf4da0ba6c0c97842b3a01822b87..fe94642e258f17445a9412b59af7eec1d9a333f0 100644 --- a/core/jni/android_server_BluetoothA2dpService.cpp +++ b/core/jni/android_server_BluetoothA2dpService.cpp @@ -45,19 +45,19 @@ static jmethodID method_onSinkPlaying; static jmethodID method_onSinkStopped; typedef struct { - JNIEnv *env; + JavaVM *vm; + int envVer; 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); +static void onConnectSinkResult(DBusMessage *msg, void *user, void *nat); +static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *nat); #endif /* Returns true on success (even if adapter is present but disabled). @@ -71,7 +71,8 @@ static bool initNative(JNIEnv* env, jobject object) { LOGE("%s: out of memory!", __FUNCTION__); return false; } - nat->env = env; + env->GetJavaVM( &(nat->vm) ); + nat->envVer = env->GetVersion(); nat->me = env->NewGlobalRef(object); DBusError err; @@ -175,7 +176,8 @@ static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) { bool ret = dbus_func_args_async(env, nat->conn, -1, - onConnectSinkResult, (void *)c_path_copy, c_path, + onConnectSinkResult, (void *)c_path_copy, nat, + c_path, "org.bluez.audio.Sink", "Connect", DBUS_TYPE_INVALID); @@ -202,7 +204,8 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object, bool ret = dbus_func_args_async(env, nat->conn, -1, - onDisconnectSinkResult, (void *)c_path_copy, c_path, + onDisconnectSinkResult, (void *)c_path_copy, nat, + c_path, "org.bluez.audio.Sink", "Disconnect", DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(path, c_path); @@ -233,13 +236,19 @@ static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) } #ifdef HAVE_BLUETOOTH -static void onConnectSinkResult(DBusMessage *msg, void *user) { +static void onConnectSinkResult(DBusMessage *msg, void *user, void *natData) { LOGV(__FUNCTION__); char *c_path = (char *)user; DBusError err; + JNIEnv *env; + + if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) { + LOGE("%s: error finding Env for our VM\n", __FUNCTION__); + return; + } + dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; LOGV("... path = %s", c_path); if (dbus_set_error_from_message(&err, msg)) { @@ -258,13 +267,19 @@ static void onConnectSinkResult(DBusMessage *msg, void *user) { free(c_path); } -static void onDisconnectSinkResult(DBusMessage *msg, void *user) { +static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *natData) { LOGV(__FUNCTION__); char *c_path = (char *)user; DBusError err; + JNIEnv *env; + + if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) { + LOGE("%s: error finding Env for our VM\n", __FUNCTION__); + return; + } + dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; LOGV("... path = %s", c_path); if (dbus_set_error_from_message(&err, msg)) { diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp index a0e0b84aed66863b7e91c30a0b3bdbb3ed7b8174..b6e979811e268501c9c1771b6d9d2c89e01018c9 100644 --- a/core/jni/android_server_BluetoothDeviceService.cpp +++ b/core/jni/android_server_BluetoothDeviceService.cpp @@ -50,6 +50,7 @@ namespace android { // We initialize these variables when we load class // android.server.BluetoothDeviceService static jfieldID field_mNativeData; +static jfieldID field_mEventLoop; typedef struct { JNIEnv *env; @@ -57,8 +58,10 @@ typedef struct { const char *adapter; // dbus object name of the local adapter } native_data_t; -void onCreateBondingResult(DBusMessage *msg, void *user); -void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user); +extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *, + jobject); +void onCreateBondingResult(DBusMessage *msg, void *user, void *nat); +void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *nat); /** Get native data stored in the opaque (Java code maintained) pointer mNativeData * Perform quick sanity check, if there are any problems return NULL @@ -78,6 +81,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) { LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH field_mNativeData = get_field(env, clazz, "mNativeData", "I"); + field_mEventLoop = get_field(env, clazz, "mEventLoop", + "Landroid/server/BluetoothEventLoop;"); #endif } @@ -472,14 +477,19 @@ static jboolean createBondingNative(JNIEnv *env, jobject object, LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); - if (nat) { + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); + + if (nat && eventLoopNat) { const char *c_address = env->GetStringUTFChars(address, NULL); LOGV("... address = %s", c_address); char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); strlcpy(context_address, c_address, BTADDR_SIZE); // for callback bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms, onCreateBondingResult, // callback - context_address, // user data + context_address, + eventLoopNat, nat->adapter, DBUS_CLASS_NAME, "CreateBonding", DBUS_TYPE_STRING, &c_address, @@ -856,7 +866,10 @@ static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object, #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); native_data_t *nat = get_native_data(env, object); - if (nat) { + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); + if (nat && eventLoopNat) { const char *c_address = env->GetStringUTFChars(address, NULL); char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); strlcpy(context_address, c_address, BTADDR_SIZE); @@ -866,6 +879,7 @@ static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object, bool ret = dbus_func_args_async(env, nat->conn, 20000, // ms onGetRemoteServiceChannelResult, context_address, + eventLoopNat, nat->adapter, DBUS_CLASS_NAME, "GetRemoteServiceChannel", DBUS_TYPE_STRING, &c_address, diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index c03bab6c2f192627b18d8ada7a1b822a0ffdc5be..7c5da5bdb5647da7b8cb08847c18dfd49708ca2d 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -18,6 +18,7 @@ #include "android_bluetooth_common.h" #include "android_runtime/AndroidRuntime.h" +#include "cutils/sockets.h" #include "JNIHelp.h" #include "jni.h" #include "utils/Log.h" @@ -65,14 +66,15 @@ static jmethodID method_onRestartRequired; typedef event_loop_native_data_t native_data_t; -// Only valid during waitForAndDispatchEventNative() -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, field_mNativeData)); } +native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) { + return get_native_data(env, object); +} + #endif static void classInitNative(JNIEnv* env, jclass clazz) { LOGV(__FUNCTION__); @@ -115,6 +117,10 @@ static void initializeNativeDataNative(JNIEnv* env, jobject object) { LOGE("%s: out of memory!", __FUNCTION__); return; } + memset(nat, 0, sizeof(native_data_t)); + + pthread_mutex_init(&(nat->thread_mutex), NULL); + env->SetIntField(object, field_mNativeData, (jint)nat); { @@ -135,6 +141,9 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) { #ifdef HAVE_BLUETOOTH native_data_t *nat = (native_data_t *)env->GetIntField(object, field_mNativeData); + + pthread_mutex_destroy(&(nat->thread_mutex)); + if (nat) { free(nat); } @@ -151,13 +160,11 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, static const DBusObjectPathVTable agent_vtable = { NULL, agent_event_filter, NULL, NULL, NULL, NULL }; -#endif -static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { -#ifdef HAVE_BLUETOOTH + +static jboolean setUpEventLoop(native_data_t *nat) { LOGV(__FUNCTION__); dbus_threads_init_default(); - native_data_t *nat = get_native_data(env, object); DBusError err; dbus_error_init(&err); @@ -207,7 +214,7 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { // Add an object handler for passkey agent method calls const char *path = "/android/bluetooth/Agent"; if (!dbus_connection_register_object_path(nat->conn, path, - &agent_vtable, NULL)) { + &agent_vtable, nat)) { LOGE("%s: Can't register object path %s for agent!", __FUNCTION__, path); return JNI_FALSE; @@ -217,7 +224,7 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { // trying for 10 seconds. int attempt; for (attempt = 0; attempt < 1000; attempt++) { - DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err, + DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "RegisterDefaultPasskeyAgent", DBUS_TYPE_STRING, &path, @@ -245,7 +252,7 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { } // Now register the Auth agent - DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err, + DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "RegisterDefaultAuthorizationAgent", DBUS_TYPE_STRING, &path, @@ -259,14 +266,11 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { return JNI_TRUE; } -#endif return JNI_FALSE; } -static void tearDownEventLoopNative(JNIEnv *env, jobject object) { +static void tearDownEventLoop(native_data_t *nat) { LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, object); if (nat != NULL && nat->conn != NULL) { DBusError err; @@ -274,14 +278,14 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) { const char *path = "/android/bluetooth/Agent"; DBusMessage *reply = - dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH, + dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "UnregisterDefaultPasskeyAgent", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); if (reply) dbus_message_unref(reply); reply = - dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH, + dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "UnregisterDefaultAuthorizationAgent", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); @@ -322,7 +326,308 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) { dbus_connection_remove_filter(nat->conn, event_filter, nat); } -#endif +} + + +#define EVENT_LOOP_EXIT 1 +#define EVENT_LOOP_ADD 2 +#define EVENT_LOOP_REMOVE 3 + +dbus_bool_t dbusAddWatch(DBusWatch *watch, void *data) { + native_data_t *nat = (native_data_t *)data; + + if (dbus_watch_get_enabled(watch)) { + // note that we can't just send the watch and inspect it later + // because we may get a removeWatch call before this data is reacted + // to by our eventloop and remove this watch.. reading the add first + // and then inspecting the recently deceased watch would be bad. + char control = EVENT_LOOP_ADD; + write(nat->controlFdW, &control, sizeof(char)); + + int fd = dbus_watch_get_fd(watch); + write(nat->controlFdW, &fd, sizeof(int)); + + unsigned int flags = dbus_watch_get_flags(watch); + write(nat->controlFdW, &flags, sizeof(unsigned int)); + + write(nat->controlFdW, &watch, sizeof(DBusWatch*)); + } + return true; +} + +void dbusRemoveWatch(DBusWatch *watch, void *data) { + native_data_t *nat = (native_data_t *)data; + + char control = EVENT_LOOP_REMOVE; + write(nat->controlFdW, &control, sizeof(char)); + + int fd = dbus_watch_get_fd(watch); + write(nat->controlFdW, &fd, sizeof(int)); + + unsigned int flags = dbus_watch_get_flags(watch); + write(nat->controlFdW, &flags, sizeof(unsigned int)); +} + +void dbusToggleWatch(DBusWatch *watch, void *data) { + if (dbus_watch_get_enabled(watch)) { + dbusAddWatch(watch, data); + } else { + dbusRemoveWatch(watch, data); + } +} + +static void handleWatchAdd(native_data_t *nat) { + DBusWatch *watch; + int newFD; + unsigned int flags; + + read(nat->controlFdR, &newFD, sizeof(int)); + read(nat->controlFdR, &flags, sizeof(unsigned int)); + read(nat->controlFdR, &watch, sizeof(DBusWatch *)); + int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0) + | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0); + + for (int y = 0; ypollMemberCount; y++) { + if ((nat->pollData[y].fd == newFD) && + (nat->pollData[y].events == events)) { + LOGV("DBusWatch duplicate add"); + return; + } + } + if (nat->pollMemberCount == nat->pollDataSize) { + LOGV("Bluetooth EventLoop poll struct growing"); + struct pollfd *temp = (struct pollfd *)malloc( + sizeof(struct pollfd) * (nat->pollMemberCount+1)); + if (!temp) { + return; + } + memcpy(temp, nat->pollData, sizeof(struct pollfd) * + nat->pollMemberCount); + free(nat->pollData); + nat->pollData = temp; + DBusWatch **temp2 = (DBusWatch **)malloc(sizeof(DBusWatch *) * + (nat->pollMemberCount+1)); + if (!temp2) { + return; + } + memcpy(temp2, nat->watchData, sizeof(DBusWatch *) * + nat->pollMemberCount); + free(nat->watchData); + nat->watchData = temp2; + nat->pollDataSize++; + } + nat->pollData[nat->pollMemberCount].fd = newFD; + nat->pollData[nat->pollMemberCount].revents = 0; + nat->pollData[nat->pollMemberCount].events = events; + nat->watchData[nat->pollMemberCount] = watch; + nat->pollMemberCount++; +} + +static void handleWatchRemove(native_data_t *nat) { + int removeFD; + unsigned int flags; + + read(nat->controlFdR, &removeFD, sizeof(int)); + read(nat->controlFdR, &flags, sizeof(unsigned int)); + int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0) + | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0); + + for (int y = 0; y < nat->pollMemberCount; y++) { + if ((nat->pollData[y].fd == removeFD) && + (nat->pollData[y].events == events)) { + int newCount = --nat->pollMemberCount; + // copy the last live member over this one + nat->pollData[y].fd = nat->pollData[newCount].fd; + nat->pollData[y].events = nat->pollData[newCount].events; + nat->pollData[y].revents = nat->pollData[newCount].revents; + nat->watchData[y] = nat->watchData[newCount]; + return; + } + } + LOGW("WatchRemove given with unknown watch"); +} + +static void *eventLoopMain(void *ptr) { + native_data_t *nat = (native_data_t *)ptr; + JNIEnv *env; + + JavaVMAttachArgs args; + char name[] = "BT EventLoop"; + args.version = nat->envVer; + args.name = name; + args.group = NULL; + + nat->vm->AttachCurrentThread(&env, &args); + + dbus_connection_set_watch_functions(nat->conn, dbusAddWatch, + dbusRemoveWatch, dbusToggleWatch, ptr, NULL); + + while (1) { + for (int i = 0; i < nat->pollMemberCount; i++) { + if (!nat->pollData[i].revents) { + continue; + } + if (nat->pollData[i].fd == nat->controlFdR) { + char data; + while (recv(nat->controlFdR, &data, sizeof(char), MSG_DONTWAIT) + != -1) { + switch (data) { + case EVENT_LOOP_EXIT: + { + dbus_connection_set_watch_functions(nat->conn, + NULL, NULL, NULL, NULL, NULL); + tearDownEventLoop(nat); + nat->vm->DetachCurrentThread(); + shutdown(nat->controlFdR,SHUT_RDWR); + return NULL; + } + case EVENT_LOOP_ADD: + { + handleWatchAdd(nat); + break; + } + case EVENT_LOOP_REMOVE: + { + handleWatchRemove(nat); + break; + } + } + } + } else { + int event = nat->pollData[i].revents; + int flags = (event & POLLIN ? DBUS_WATCH_READABLE : 0) | + (event & POLLOUT ? DBUS_WATCH_WRITABLE : 0); + dbus_watch_handle(nat->watchData[i], event); + nat->pollData[i].revents = 0; + // can only do one - it may have caused a 'remove' + break; + } + } + while (dbus_connection_dispatch(nat->conn) == + DBUS_DISPATCH_DATA_REMAINS) { + } + + poll(nat->pollData, nat->pollMemberCount, -1); + } +} +#endif // HAVE_BLUETOOTH + +static jboolean startEventLoopNative(JNIEnv *env, jobject object) { + jboolean result = JNI_FALSE; +#ifdef HAVE_BLUETOOTH + event_loop_native_data_t *nat = get_native_data(env, object); + + pthread_mutex_lock(&(nat->thread_mutex)); + + if (nat->pollData) { + LOGW("trying to start EventLoop a second time!"); + pthread_mutex_unlock( &(nat->thread_mutex) ); + return JNI_FALSE; + } + + nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) * + DEFAULT_INITIAL_POLLFD_COUNT); + if (!nat->pollData) { + LOGE("out of memory error starting EventLoop!"); + goto done; + } + + nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) * + DEFAULT_INITIAL_POLLFD_COUNT); + if (!nat->watchData) { + LOGE("out of memory error starting EventLoop!"); + goto done; + } + + memset(nat->pollData, 0, sizeof(struct pollfd) * + DEFAULT_INITIAL_POLLFD_COUNT); + memset(nat->watchData, 0, sizeof(DBusWatch *) * + DEFAULT_INITIAL_POLLFD_COUNT); + nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT; + nat->pollMemberCount = 1; + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) { + LOGE("Error getting BT control socket"); + goto done; + } + nat->pollData[0].fd = nat->controlFdR; + nat->pollData[0].events = POLLIN; + + env->GetJavaVM( &(nat->vm) ); + nat->envVer = env->GetVersion(); + + nat->me = env->NewGlobalRef(object); + + if (setUpEventLoop(nat) != JNI_TRUE) { + LOGE("failure setting up Event Loop!"); + goto done; + } + + pthread_create(&(nat->thread), NULL, eventLoopMain, nat); + result = JNI_TRUE; + +done: + if (JNI_FALSE == result) { + if (nat->controlFdW || nat->controlFdR) { + shutdown(nat->controlFdW, SHUT_RDWR); + nat->controlFdW = 0; + nat->controlFdR = 0; + } + if (nat->me) env->DeleteGlobalRef(nat->me); + nat->me = NULL; + if (nat->pollData) free(nat->pollData); + nat->pollData = NULL; + if (nat->watchData) free(nat->watchData); + nat->watchData = NULL; + nat->pollDataSize = 0; + nat->pollMemberCount = 0; + } + + pthread_mutex_unlock(&(nat->thread_mutex)); +#endif // HAVE_BLUETOOTH + return result; +} + +static void stopEventLoopNative(JNIEnv *env, jobject object) { +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + + pthread_mutex_lock(&(nat->thread_mutex)); + if (nat->pollData) { + char data = EVENT_LOOP_EXIT; + ssize_t t = write(nat->controlFdW, &data, sizeof(char)); + void *ret; + pthread_join(nat->thread, &ret); + + env->DeleteGlobalRef(nat->me); + nat->me = NULL; + free(nat->pollData); + nat->pollData = NULL; + free(nat->watchData); + nat->watchData = NULL; + nat->pollDataSize = 0; + nat->pollMemberCount = 0; + shutdown(nat->controlFdW, SHUT_RDWR); + nat->controlFdW = 0; + nat->controlFdR = 0; + } + pthread_mutex_unlock(&(nat->thread_mutex)); +#endif // HAVE_BLUETOOTH +} + +static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) { + jboolean result = JNI_FALSE; +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + + pthread_mutex_lock(&(nat->thread_mutex)); + if (nat->pollData) { + result = JNI_TRUE; + } + pthread_mutex_unlock(&(nat->thread_mutex)); + +#endif // HAVE_BLUETOOTH + return result; } #ifdef HAVE_BLUETOOTH @@ -338,7 +643,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, dbus_error_init(&err); nat = (native_data_t *)data; - env = nat->env; + nat->vm->GetEnv((void**)&env, nat->envVer); if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) { LOGV("%s: not interested (not a signal).", __FUNCTION__); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -556,11 +861,9 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, // Called by dbus during WaitForAndDispatchEventNative() static DBusHandlerResult agent_event_filter(DBusConnection *conn, DBusMessage *msg, void *data) { - native_data_t *nat = event_loop_nat; + native_data_t *nat = (native_data_t *)data; JNIEnv *env; - - - env = nat->env; + nat->vm->GetEnv((void**)&env, nat->envVer); if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) { LOGV("%s: not interested (not a method call).", __FUNCTION__); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -730,27 +1033,6 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, } #endif -static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object, - jint timeout_ms) { -#ifdef HAVE_BLUETOOTH - //LOGV("%s: %8d (pid %d tid %d)",__FUNCTION__, time(NULL), getpid(), gettid()); // too chatty - native_data_t *nat = get_native_data(env, object); - if (nat != NULL && nat->conn != NULL) { - jboolean ret; - nat->me = object; - nat->env = env; - event_loop_nat = nat; - 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; - return ret; - } -#endif - return JNI_FALSE; -} #ifdef HAVE_BLUETOOTH //TODO: Unify result codes in a header @@ -761,13 +1043,16 @@ static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object, #define BOND_RESULT_AUTH_CANCELED 3 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5 -void onCreateBondingResult(DBusMessage *msg, void *user) { + +void onCreateBondingResult(DBusMessage *msg, void *user, void *n) { LOGV(__FUNCTION__); + native_data_t *nat = (native_data_t *)n; const char *address = (const char *)user; DBusError err; dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; + JNIEnv *env; + nat->vm->GetEnv((void**)&env, nat->envVer); LOGV("... address = %s", address); @@ -809,7 +1094,7 @@ void onCreateBondingResult(DBusMessage *msg, void *user) { } } - env->CallVoidMethod(event_loop_nat->me, + env->CallVoidMethod(nat->me, method_onCreateBondingResult, env->NewStringUTF(address), result); @@ -818,13 +1103,17 @@ done: free(user); } -void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) { +void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) { LOGV(__FUNCTION__); const char *address = (const char *) user; + native_data_t *nat = (native_data_t *) n; + DBusError err; dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; + JNIEnv *env; + nat->vm->GetEnv((void**)&env, nat->envVer); + jint channel = -2; LOGV("... address = %s", address); @@ -839,7 +1128,7 @@ void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) { } done: - env->CallVoidMethod(event_loop_nat->me, + env->CallVoidMethod(nat->me, method_onGetRemoteServiceChannelResult, env->NewStringUTF(address), channel); @@ -852,9 +1141,9 @@ static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void *)classInitNative}, {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, - {"setUpEventLoopNative", "()Z", (void *)setUpEventLoopNative}, - {"tearDownEventLoopNative", "()V", (void *)tearDownEventLoopNative}, - {"waitForAndDispatchEventNative", "(I)Z", (void *)waitForAndDispatchEventNative} + {"startEventLoopNative", "()V", (void *)startEventLoopNative}, + {"stopEventLoopNative", "()V", (void *)stopEventLoopNative}, + {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative} }; int register_android_server_BluetoothEventLoop(JNIEnv *env) { diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 3feccde03c311e88e8e6ba37f34cda0646b4f57b..d760feb3a3aabd4880e923694177ae9173fe1bb0 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -50,6 +50,16 @@ pid_t gettid() { return syscall(__NR_gettid);} #undef __KERNEL__ #endif +#define ENABLE_CGROUP_ERR_LOGGING 0 + +/* + * List of cgroup names which map to ANDROID_TGROUP_ values in Thread.h + * and Process.java + * These names are used to construct the path to the cgroup control dir + */ + +static const char *cgroup_names[] = { NULL, "bg_non_interactive", "fg_boost" }; + using namespace android; static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err) @@ -73,6 +83,28 @@ static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err) } } +static void signalExceptionForGroupError(JNIEnv* env, jobject obj, int err) +{ + switch (err) { + case EINVAL: + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + break; + case ESRCH: + jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist"); + break; + case EPERM: + jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread"); + break; + case EACCES: + jniThrowException(env, "java/lang/SecurityException", "No permission to set to given group"); + break; + default: + jniThrowException(env, "java/lang/RuntimeException", "Unknown error"); + break; + } +} + + static void fakeProcessEntry(void* arg) { String8* cls = (String8*)arg; @@ -164,9 +196,55 @@ jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name) return -1; } +static int add_pid_to_cgroup(int pid, int grp) +{ + FILE *fp; + char path[255]; + int rc; + + sprintf(path, "/dev/cpuctl/%s/tasks", (cgroup_names[grp] ? cgroup_names[grp] : "")); + + if (!(fp = fopen(path, "w"))) { +#if ENABLE_CGROUP_ERR_LOGGING + LOGW("Unable to open %s (%s)\n", path, strerror(errno)); +#endif + return -errno; + } + + rc = fprintf(fp, "%d", pid); + fclose(fp); + + if (rc < 0) { +#if ENABLE_CGROUP_ERR_LOGGING + LOGW("Unable to move pid %d to cgroup %s (%s)\n", pid, + (cgroup_names[grp] ? cgroup_names[grp] : ""), + strerror(errno)); +#endif + } + + return (rc < 0) ? errno : 0; +} + +void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp) +{ + if (grp > ANDROID_TGROUP_MAX || grp < 0) { + signalExceptionForGroupError(env, clazz, EINVAL); + return; + } + + if (add_pid_to_cgroup(pid, grp)) + signalExceptionForGroupError(env, clazz, errno); +} + void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz, jint pid, jint pri) { + if (pri == ANDROID_PRIORITY_BACKGROUND) { + add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT); + } else if (getpriority(PRIO_PROCESS, pid) == ANDROID_PRIORITY_BACKGROUND) { + add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT); + } + if (setpriority(PRIO_PROCESS, pid, pri) < 0) { signalExceptionForPriorityError(env, clazz, errno); } @@ -516,39 +594,10 @@ enum { PROC_OUT_FLOAT = 0x4000, }; -jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, - jstring file, jintArray format, jobjectArray outStrings, - jlongArray outLongs, jfloatArray outFloats) +jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz, + char* buffer, jint startIndex, jint endIndex, jintArray format, + jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) { - if (file == NULL || format == NULL) { - jniThrowException(env, "java/lang/NullPointerException", NULL); - return JNI_FALSE; - } - - const char* file8 = env->GetStringUTFChars(file, NULL); - if (file8 == NULL) { - jniThrowException(env, "java/lang/OutOfMemoryError", NULL); - return JNI_FALSE; - } - int fd = open(file8, O_RDONLY); - env->ReleaseStringUTFChars(file, file8); - - if (fd < 0) { - //LOGW("Unable to open process file: %s\n", file8); - return JNI_FALSE; - } - - char buffer[256]; - const int len = read(fd, buffer, sizeof(buffer)-1); - close(fd); - - if (len < 0) { - //LOGW("Unable to open process file: %s fd=%d\n", file8, fd); - return JNI_FALSE; - } - buffer[len] = 0; - - //LOGI("Process file %s: %s\n", file8, buffer); const jsize NF = env->GetArrayLength(format); const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0; @@ -575,7 +624,7 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, return JNI_FALSE; } - jsize i = 0; + jsize i = startIndex; jsize di = 0; jboolean res = JNI_TRUE; @@ -587,30 +636,30 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, } const char term = (char)(mode&PROC_TERM_MASK); const jsize start = i; - if (i >= len) { + if (i >= endIndex) { res = JNI_FALSE; break; } jsize end = -1; if ((mode&PROC_PARENS) != 0) { - while (buffer[i] != ')' && i < len) { + while (buffer[i] != ')' && i < endIndex) { i++; } end = i; i++; } - while (buffer[i] != term && i < len) { + while (buffer[i] != term && i < endIndex) { i++; } if (end < 0) { end = i; } - if (i < len) { + if (i < endIndex) { i++; if ((mode&PROC_COMBINE) != 0) { - while (buffer[i] == term && i < len) { + while (buffer[i] == term && i < endIndex) { i++; } } @@ -649,6 +698,58 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, return res; } +jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz, + jbyteArray buffer, jint startIndex, jint endIndex, jintArray format, + jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats) +{ + jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL); + + jboolean result = android_os_Process_parseProcLineArray(env, clazz, + (char*) bufferArray, startIndex, endIndex, format, outStrings, + outLongs, outFloats); + + env->ReleaseByteArrayElements(buffer, bufferArray, 0); + + return result; +} + +jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, + jstring file, jintArray format, jobjectArray outStrings, + jlongArray outLongs, jfloatArray outFloats) +{ + if (file == NULL || format == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return JNI_FALSE; + } + + const char* file8 = env->GetStringUTFChars(file, NULL); + if (file8 == NULL) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return JNI_FALSE; + } + int fd = open(file8, O_RDONLY); + env->ReleaseStringUTFChars(file, file8); + + if (fd < 0) { + //LOGW("Unable to open process file: %s\n", file8); + return JNI_FALSE; + } + + char buffer[256]; + const int len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + + if (len < 0) { + //LOGW("Unable to open process file: %s fd=%d\n", file8, fd); + return JNI_FALSE; + } + buffer[len] = 0; + + return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len, + format, outStrings, outLongs, outFloats); + +} + void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz, jobject binderObject) { @@ -718,6 +819,7 @@ static const JNINativeMethod methods[] = { {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority}, {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority}, {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority}, + {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup}, {"setOomAdj", "(II)Z", (void*)android_os_Process_setOomAdj}, {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0}, {"setUid", "(I)I", (void*)android_os_Process_setUid}, @@ -728,6 +830,7 @@ static const JNINativeMethod methods[] = { {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines}, {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids}, {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile}, + {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine}, {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime}, {"getPss", "(I)J", (void*)android_os_Process_getPss}, //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject}, @@ -746,4 +849,3 @@ int register_android_os_Process(JNIEnv* env) env, kProcessPathName, methods, NELEM(methods)); } - diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp index 9b09c9b82c0b4f9c16f5b95e25b1f872bd979e1c..11822e014d9c5ca126701a6004d8abbb5e4691bf 100644 --- a/core/jni/com_google_android_gles_jni_GLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp @@ -22,11 +22,20 @@ #include #include +#include -#include - -#define _NUM_COMPRESSED_TEXTURE_FORMATS \ - (::android::OGLES_NUM_COMPRESSED_TEXTURE_FORMATS) +/* special calls implemented in Android's GLES wrapper used to more + * efficiently bound-check passed arrays */ +extern "C" { +GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, + const GLvoid *ptr, GLsizei count); +GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, + const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +} static int initialized = 0; @@ -45,7 +54,7 @@ static jfieldID elementSizeShiftID; /* Cache method IDs each time the class is loaded. */ -void +static void nativeClassInitBuffer(JNIEnv *_env) { jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); @@ -67,7 +76,6 @@ nativeClassInitBuffer(JNIEnv *_env) _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { @@ -118,7 +126,6 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) return (void *) ((char *) data + offset); } - static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { @@ -126,6 +133,13 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) commit ? 0 : JNI_ABORT); } +static int +getNumCompressedTextureFormats() { + int numCompressedTextureFormats = 0; + glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedTextureFormats); + return numCompressedTextureFormats; +} + // -------------------------------------------------------------------------- /* void glActiveTexture ( GLenum texture ) */ @@ -290,7 +304,13 @@ android_glColorPointerBounds__IIILjava_nio_Buffer_2I jint _remaining; GLvoid *pointer = (GLvoid *) 0; - pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining); + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } glColorPointerBounds( (GLint)size, (GLenum)type, @@ -298,9 +318,6 @@ android_glColorPointerBounds__IIILjava_nio_Buffer_2I (GLvoid *)pointer, (GLsizei)remaining ); - if (_array) { - releasePointer(_env, _array, pointer, JNI_FALSE); - } } /* void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) */ @@ -1022,6 +1039,12 @@ android_glGetIntegerv__I_3II #if defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: #endif // defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) +#if defined(GL_LIGHT_MODEL_COLOR_CONTROL) + case GL_LIGHT_MODEL_COLOR_CONTROL: +#endif // defined(GL_LIGHT_MODEL_COLOR_CONTROL) +#if defined(GL_LIGHT_MODEL_LOCAL_VIEWER) + case GL_LIGHT_MODEL_LOCAL_VIEWER: +#endif // defined(GL_LIGHT_MODEL_LOCAL_VIEWER) #if defined(GL_LIGHT_MODEL_TWO_SIDE) case GL_LIGHT_MODEL_TWO_SIDE: #endif // defined(GL_LIGHT_MODEL_TWO_SIDE) @@ -1236,6 +1259,12 @@ android_glGetIntegerv__I_3II #if defined(GL_COLOR_WRITEMASK) case GL_COLOR_WRITEMASK: #endif // defined(GL_COLOR_WRITEMASK) +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) #if defined(GL_SCISSOR_BOX) case GL_SCISSOR_BOX: #endif // defined(GL_SCISSOR_BOX) @@ -1267,13 +1296,7 @@ android_glGetIntegerv__I_3II #if defined(GL_COMPRESSED_TEXTURE_FORMATS) case GL_COMPRESSED_TEXTURE_FORMATS: #endif // defined(GL_COMPRESSED_TEXTURE_FORMATS) -#if defined(GL_FOG_COLOR) - case GL_FOG_COLOR: -#endif // defined(GL_FOG_COLOR) -#if defined(GL_LIGHT_MODEL_AMBIENT) - case GL_LIGHT_MODEL_AMBIENT: -#endif // defined(GL_LIGHT_MODEL_AMBIENT) - _needed = _NUM_COMPRESSED_TEXTURE_FORMATS; + _needed = getNumCompressedTextureFormats(); break; default: _needed = 0; @@ -1378,6 +1401,12 @@ android_glGetIntegerv__ILjava_nio_IntBuffer_2 #if defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: #endif // defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES) +#if defined(GL_LIGHT_MODEL_COLOR_CONTROL) + case GL_LIGHT_MODEL_COLOR_CONTROL: +#endif // defined(GL_LIGHT_MODEL_COLOR_CONTROL) +#if defined(GL_LIGHT_MODEL_LOCAL_VIEWER) + case GL_LIGHT_MODEL_LOCAL_VIEWER: +#endif // defined(GL_LIGHT_MODEL_LOCAL_VIEWER) #if defined(GL_LIGHT_MODEL_TWO_SIDE) case GL_LIGHT_MODEL_TWO_SIDE: #endif // defined(GL_LIGHT_MODEL_TWO_SIDE) @@ -1592,6 +1621,12 @@ android_glGetIntegerv__ILjava_nio_IntBuffer_2 #if defined(GL_COLOR_WRITEMASK) case GL_COLOR_WRITEMASK: #endif // defined(GL_COLOR_WRITEMASK) +#if defined(GL_FOG_COLOR) + case GL_FOG_COLOR: +#endif // defined(GL_FOG_COLOR) +#if defined(GL_LIGHT_MODEL_AMBIENT) + case GL_LIGHT_MODEL_AMBIENT: +#endif // defined(GL_LIGHT_MODEL_AMBIENT) #if defined(GL_SCISSOR_BOX) case GL_SCISSOR_BOX: #endif // defined(GL_SCISSOR_BOX) @@ -1623,13 +1658,7 @@ android_glGetIntegerv__ILjava_nio_IntBuffer_2 #if defined(GL_COMPRESSED_TEXTURE_FORMATS) case GL_COMPRESSED_TEXTURE_FORMATS: #endif // defined(GL_COMPRESSED_TEXTURE_FORMATS) -#if defined(GL_FOG_COLOR) - case GL_FOG_COLOR: -#endif // defined(GL_FOG_COLOR) -#if defined(GL_LIGHT_MODEL_AMBIENT) - case GL_LIGHT_MODEL_AMBIENT: -#endif // defined(GL_LIGHT_MODEL_AMBIENT) - _needed = _NUM_COMPRESSED_TEXTURE_FORMATS; + _needed = getNumCompressedTextureFormats(); break; default: _needed = 0; @@ -1654,6 +1683,7 @@ exit: #include /* const GLubyte * glGetString ( GLenum name ) */ +static jstring android_glGetString (JNIEnv *_env, jobject _this, jint name) { @@ -2748,16 +2778,19 @@ android_glNormalPointerBounds__IILjava_nio_Buffer_2I jint _remaining; GLvoid *pointer = (GLvoid *) 0; - pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining); + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } glNormalPointerBounds( (GLenum)type, (GLsizei)stride, (GLvoid *)pointer, (GLsizei)remaining ); - if (_array) { - releasePointer(_env, _array, pointer, JNI_FALSE); - } } /* void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */ @@ -3000,7 +3033,13 @@ android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I jint _remaining; GLvoid *pointer = (GLvoid *) 0; - pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining); + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } glTexCoordPointerBounds( (GLint)size, (GLenum)type, @@ -3008,9 +3047,6 @@ android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I (GLvoid *)pointer, (GLsizei)remaining ); - if (_array) { - releasePointer(_env, _array, pointer, JNI_FALSE); - } } /* void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) */ @@ -3355,7 +3391,13 @@ android_glVertexPointerBounds__IIILjava_nio_Buffer_2I jint _remaining; GLvoid *pointer = (GLvoid *) 0; - pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining); + if (pointer_buf) { + pointer = (GLvoid *) _env->GetDirectBufferAddress(pointer_buf); + if ( ! pointer ) { + _env->ThrowNew(IAEClass, "Must use a native order direct Buffer"); + return; + } + } glVertexPointerBounds( (GLint)size, (GLenum)type, @@ -3363,9 +3405,6 @@ android_glVertexPointerBounds__IIILjava_nio_Buffer_2I (GLvoid *)pointer, (GLsizei)remaining ); - if (_array) { - releasePointer(_env, _array, pointer, JNI_FALSE); - } } /* void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9f6ebeded2ae600261d0c29b6aa1933bf99575ff..bff6b9dfda5e63313e49405923c00544a97f3998 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -214,6 +214,18 @@ android:label="@string/permlab_accessLocationExtraCommands" android:description="@string/permdesc_accessLocationExtraCommands" /> + + + + + + @@ -366,6 +378,23 @@ android:label="@string/permlab_readPhoneState" android:description="@string/permdesc_readPhoneState" /> + + + + + + + + + + + @@ -774,6 +803,14 @@ android:description="@string/permdesc_runSetActivityWatcher" android:protectionLevel="signature" /> + + + + android:protectionLevel="signatureOrSystem" /> @@ -983,9 +1020,6 @@ android:excludeFromRecents="true"> - - diff --git a/core/res/res/anim/anticipate_interpolator.xml b/core/res/res/anim/anticipate_interpolator.xml new file mode 100644 index 0000000000000000000000000000000000000000..50a555a6766c0c0787c80b40419f5051088e95fd --- /dev/null +++ b/core/res/res/anim/anticipate_interpolator.xml @@ -0,0 +1,21 @@ + + + + diff --git a/core/res/res/anim/anticipate_overshoot_interpolator.xml b/core/res/res/anim/anticipate_overshoot_interpolator.xml new file mode 100644 index 0000000000000000000000000000000000000000..440a899f954917ca65fe42896b78596cff60eec9 --- /dev/null +++ b/core/res/res/anim/anticipate_overshoot_interpolator.xml @@ -0,0 +1,21 @@ + + + + diff --git a/core/res/res/anim/bounce_interpolator.xml b/core/res/res/anim/bounce_interpolator.xml new file mode 100644 index 0000000000000000000000000000000000000000..406fbb9fd159157777270dcafa4647f05548737d --- /dev/null +++ b/core/res/res/anim/bounce_interpolator.xml @@ -0,0 +1,21 @@ + + + + diff --git a/core/res/res/anim/overshoot_interpolator.xml b/core/res/res/anim/overshoot_interpolator.xml new file mode 100644 index 0000000000000000000000000000000000000000..c614e0b8f0d33e02fe665c3171ab2601c2504c90 --- /dev/null +++ b/core/res/res/anim/overshoot_interpolator.xml @@ -0,0 +1,21 @@ + + + + diff --git a/core/res/res/drawable/btn_global_search.xml b/core/res/res/drawable/btn_global_search.xml new file mode 100644 index 0000000000000000000000000000000000000000..531f07eb90b8e354d981986e6121151484d8b6ef --- /dev/null +++ b/core/res/res/drawable/btn_global_search.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/core/res/res/drawable/btn_global_search_normal.9.png b/core/res/res/drawable/btn_global_search_normal.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9b7d3e5cd832a0ab155b43267b21e690a660564b Binary files /dev/null and b/core/res/res/drawable/btn_global_search_normal.9.png differ diff --git a/core/res/res/drawable/btn_search_dialog.xml b/core/res/res/drawable/btn_search_dialog.xml new file mode 100644 index 0000000000000000000000000000000000000000..b7f51875a7e39fee3e1f645fd6c6f957b2b0bf3f --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + diff --git a/core/res/res/drawable/btn_search_dialog_default.9.png b/core/res/res/drawable/btn_search_dialog_default.9.png new file mode 100644 index 0000000000000000000000000000000000000000..7275231879be6f89452690bc0bb2d3494d63f494 Binary files /dev/null and b/core/res/res/drawable/btn_search_dialog_default.9.png differ diff --git a/core/res/res/drawable/btn_search_dialog_pressed.9.png b/core/res/res/drawable/btn_search_dialog_pressed.9.png new file mode 100644 index 0000000000000000000000000000000000000000..50a920978874a4be195333639368012b2e51e216 Binary files /dev/null and b/core/res/res/drawable/btn_search_dialog_pressed.9.png differ diff --git a/core/res/res/drawable/btn_search_dialog_selected.9.png b/core/res/res/drawable/btn_search_dialog_selected.9.png new file mode 100644 index 0000000000000000000000000000000000000000..14b774a376ccb087199af81ceca2e5811a34bff8 Binary files /dev/null and b/core/res/res/drawable/btn_search_dialog_selected.9.png differ diff --git a/core/res/res/drawable/btn_search_dialog_voice.xml b/core/res/res/drawable/btn_search_dialog_voice.xml new file mode 100644 index 0000000000000000000000000000000000000000..748aaf50849db8fbe36faa3ce034abe6bf37fa31 --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog_voice.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + diff --git a/core/res/res/drawable/btn_search_dialog_voice_default.9.png b/core/res/res/drawable/btn_search_dialog_voice_default.9.png new file mode 100644 index 0000000000000000000000000000000000000000..febf2223eb54a1244236e859924dfafa3e7eb4b7 Binary files /dev/null and b/core/res/res/drawable/btn_search_dialog_voice_default.9.png differ diff --git a/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png b/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png new file mode 100644 index 0000000000000000000000000000000000000000..70a200b96057cf9c39afd90b149f4b387fc921be Binary files /dev/null and b/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png differ diff --git a/core/res/res/drawable/btn_search_dialog_voice_selected.9.png b/core/res/res/drawable/btn_search_dialog_voice_selected.9.png new file mode 100644 index 0000000000000000000000000000000000000000..6f2989fa1f953be532539ab960a3f11d16633256 Binary files /dev/null and b/core/res/res/drawable/btn_search_dialog_voice_selected.9.png differ diff --git a/core/res/res/drawable/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png new file mode 100644 index 0000000000000000000000000000000000000000..30c9b2b63e4abd6596da978f9cceb26c842e3e9a Binary files /dev/null and b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png differ diff --git a/core/res/res/drawable/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png new file mode 100644 index 0000000000000000000000000000000000000000..ce21acd8a9d4203967849a0c2e19d71ff029a74b Binary files /dev/null and b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png differ diff --git a/core/res/res/drawable/ic_contact_picture.png b/core/res/res/drawable/ic_contact_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..3a338e8e219bfc4f2ea7a2cad847479855e7435a Binary files /dev/null and b/core/res/res/drawable/ic_contact_picture.png differ diff --git a/core/res/res/drawable/search_dropdown_background.9.png b/core/res/res/drawable/search_dropdown_background.9.png new file mode 100755 index 0000000000000000000000000000000000000000..a6923b7c01363d780ffd82c30f94562ddc2eb458 Binary files /dev/null and b/core/res/res/drawable/search_dropdown_background.9.png differ diff --git a/core/res/res/drawable/search_dropdown_background_apps.9.png b/core/res/res/drawable/search_dropdown_background_apps.9.png new file mode 100644 index 0000000000000000000000000000000000000000..56b697d97b8e738ffa2aed8fc1c8dc4f5e87eb9a Binary files /dev/null and b/core/res/res/drawable/search_dropdown_background_apps.9.png differ diff --git a/core/res/res/drawable/search_plate_global.9.png b/core/res/res/drawable/search_plate_global.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1cad9020d564941d8179a1edef98a1dbe6db2794 Binary files /dev/null and b/core/res/res/drawable/search_plate_global.9.png differ diff --git a/core/res/res/drawable/stat_sys_data_connected_1xrtt.png b/core/res/res/drawable/stat_sys_data_connected_1xrtt.png new file mode 100644 index 0000000000000000000000000000000000000000..c2fbbdfbc4faf315a2292bf6a6103875eca70da2 Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_connected_1xrtt.png differ diff --git a/core/res/res/drawable/stat_sys_data_connected_evdo.png b/core/res/res/drawable/stat_sys_data_connected_evdo.png new file mode 100644 index 0000000000000000000000000000000000000000..db9f282e7b970a911ce78feb1e0a1d00a5ca6659 Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_connected_evdo.png differ diff --git a/core/res/res/drawable/stat_sys_data_in_1xrtt.png b/core/res/res/drawable/stat_sys_data_in_1xrtt.png new file mode 100644 index 0000000000000000000000000000000000000000..a421a8a45bba4949a082058b77d81201c11b172f Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_in_1xrtt.png differ diff --git a/core/res/res/drawable/stat_sys_data_in_evdo.png b/core/res/res/drawable/stat_sys_data_in_evdo.png new file mode 100644 index 0000000000000000000000000000000000000000..54f55bac0ad88c3e1e3f3cd27880f4e19f452059 Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_in_evdo.png differ diff --git a/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png b/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png new file mode 100644 index 0000000000000000000000000000000000000000..1a94cdfe0b6f57f7ddb895c9c9ed3b93be452eb9 Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png differ diff --git a/core/res/res/drawable/stat_sys_data_inandout_evdo.png b/core/res/res/drawable/stat_sys_data_inandout_evdo.png new file mode 100644 index 0000000000000000000000000000000000000000..7aa6f00f2ddea2e57b7b6077ac74a851e287b998 Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_inandout_evdo.png differ diff --git a/core/res/res/drawable/stat_sys_data_out_1xrtt.png b/core/res/res/drawable/stat_sys_data_out_1xrtt.png new file mode 100644 index 0000000000000000000000000000000000000000..74fd351e564c558a76070ea4423341deaea82a05 Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_out_1xrtt.png differ diff --git a/core/res/res/drawable/stat_sys_data_out_evdo.png b/core/res/res/drawable/stat_sys_data_out_evdo.png new file mode 100644 index 0000000000000000000000000000000000000000..21e19a713f936abaf0ca8c9f2949e53382106044 Binary files /dev/null and b/core/res/res/drawable/stat_sys_data_out_evdo.png differ diff --git a/core/res/res/drawable/stat_sys_r_signal_0_cdma.png b/core/res/res/drawable/stat_sys_r_signal_0_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..f6156814002f79739185b9daea06e53ab47bc959 Binary files /dev/null and b/core/res/res/drawable/stat_sys_r_signal_0_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_r_signal_1_cdma.png b/core/res/res/drawable/stat_sys_r_signal_1_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..c3962a2e01f4fd58cdce799203a478f14e85f9dc Binary files /dev/null and b/core/res/res/drawable/stat_sys_r_signal_1_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_r_signal_2_cdma.png b/core/res/res/drawable/stat_sys_r_signal_2_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..68bfe94f2c27c27e7f826554f9d6518b18daca3b Binary files /dev/null and b/core/res/res/drawable/stat_sys_r_signal_2_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_r_signal_3_cdma.png b/core/res/res/drawable/stat_sys_r_signal_3_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..4ccd416ecc8c00ab39f5ad068961130c4344f99d Binary files /dev/null and b/core/res/res/drawable/stat_sys_r_signal_3_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_r_signal_4_cdma.png b/core/res/res/drawable/stat_sys_r_signal_4_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..0b255705a903cdbac434ae659bab19ba640866a7 Binary files /dev/null and b/core/res/res/drawable/stat_sys_r_signal_4_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_ra_signal_0_cdma.png b/core/res/res/drawable/stat_sys_ra_signal_0_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..9a38733ac64184dd0d041669bd3f9e03fec3276b Binary files /dev/null and b/core/res/res/drawable/stat_sys_ra_signal_0_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_ra_signal_1_cdma.png b/core/res/res/drawable/stat_sys_ra_signal_1_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..c70e283b3d1eca52965ccb494ff85e1671c9ea08 Binary files /dev/null and b/core/res/res/drawable/stat_sys_ra_signal_1_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_ra_signal_2_cdma.png b/core/res/res/drawable/stat_sys_ra_signal_2_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..a09564c9782f9de4ff8deb1c7f858d595609bc06 Binary files /dev/null and b/core/res/res/drawable/stat_sys_ra_signal_2_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_ra_signal_3_cdma.png b/core/res/res/drawable/stat_sys_ra_signal_3_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..2637dec17ca3904fc864d40c19c520392ca58c1f Binary files /dev/null and b/core/res/res/drawable/stat_sys_ra_signal_3_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_ra_signal_4_cdma.png b/core/res/res/drawable/stat_sys_ra_signal_4_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..aba13e7dd56b61c057756586f7e7164cde1da723 Binary files /dev/null and b/core/res/res/drawable/stat_sys_ra_signal_4_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_signal_0_cdma.png b/core/res/res/drawable/stat_sys_signal_0_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..0ef7d534c3711c039d13ffec19c575592eb98868 Binary files /dev/null and b/core/res/res/drawable/stat_sys_signal_0_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_signal_1_cdma.png b/core/res/res/drawable/stat_sys_signal_1_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..f4839d4954fea0a9d07718b2ede327e602821b13 Binary files /dev/null and b/core/res/res/drawable/stat_sys_signal_1_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_signal_2_cdma.png b/core/res/res/drawable/stat_sys_signal_2_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..e25a99cff692649d46b275c0e1e8fd73d26b81d1 Binary files /dev/null and b/core/res/res/drawable/stat_sys_signal_2_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_signal_3_cdma.png b/core/res/res/drawable/stat_sys_signal_3_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..d828d99a5b0875603558711ff70b7f21d6c9f71f Binary files /dev/null and b/core/res/res/drawable/stat_sys_signal_3_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_signal_4_cdma.png b/core/res/res/drawable/stat_sys_signal_4_cdma.png new file mode 100644 index 0000000000000000000000000000000000000000..53a31ea89e90b65979f7847bd5366a99e06d6e66 Binary files /dev/null and b/core/res/res/drawable/stat_sys_signal_4_cdma.png differ diff --git a/core/res/res/drawable/stat_sys_tty_mode.png b/core/res/res/drawable/stat_sys_tty_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..ed157a8722a4901f4316a21deb75ac73569efb64 Binary files /dev/null and b/core/res/res/drawable/stat_sys_tty_mode.png differ diff --git a/core/res/res/drawable/stat_sys_vp_phone_call.png b/core/res/res/drawable/stat_sys_vp_phone_call.png new file mode 100644 index 0000000000000000000000000000000000000000..aa03b4f55c20dc8841c9457da175895ed4c294b9 Binary files /dev/null and b/core/res/res/drawable/stat_sys_vp_phone_call.png differ diff --git a/core/res/res/drawable/stat_sys_vp_phone_call_on_hold.png b/core/res/res/drawable/stat_sys_vp_phone_call_on_hold.png new file mode 100644 index 0000000000000000000000000000000000000000..5f454409b4244307c8f7e5e6a4555c266c1abc18 Binary files /dev/null and b/core/res/res/drawable/stat_sys_vp_phone_call_on_hold.png differ diff --git a/core/res/res/drawable/textfield_search.xml b/core/res/res/drawable/textfield_search.xml new file mode 100644 index 0000000000000000000000000000000000000000..292336870f7ec7011c7dd7a9cba892fd7b13c0cf --- /dev/null +++ b/core/res/res/drawable/textfield_search.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/core/res/res/drawable/textfield_search_default.9.png b/core/res/res/drawable/textfield_search_default.9.png new file mode 100755 index 0000000000000000000000000000000000000000..7dc5b271f27a61fd3569af095187cc96a151d124 Binary files /dev/null and b/core/res/res/drawable/textfield_search_default.9.png differ diff --git a/core/res/res/drawable/textfield_search_pressed.9.png b/core/res/res/drawable/textfield_search_pressed.9.png new file mode 100644 index 0000000000000000000000000000000000000000..da00c2579e12a2b71a4c5098678a0a0c626be420 Binary files /dev/null and b/core/res/res/drawable/textfield_search_pressed.9.png differ diff --git a/core/res/res/drawable/textfield_search_selected.9.png b/core/res/res/drawable/textfield_search_selected.9.png new file mode 100755 index 0000000000000000000000000000000000000000..a9fd3b28b20fa06c806d395e67f55289745160cd Binary files /dev/null and b/core/res/res/drawable/textfield_search_selected.9.png differ diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml index 5e296c56ebe4092aef4114de268e2e54b0fabd39..4c5c456a20267cdcda746ba2d50f8a3038a2742d 100644 --- a/core/res/res/layout/resolve_list_item.xml +++ b/core/res/res/layout/resolve_list_item.xml @@ -23,7 +23,7 @@ android:minHeight="?android:attr/listPreferredItemHeight" android:layout_height="wrap_content" android:layout_width="fill_parent" - android:paddingLeft="14dip" + android:paddingLeft="10dip" android:paddingRight="15dip"> @@ -42,13 +42,13 @@ android:textAppearance="?android:attr/textAppearanceLargeInverse" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingLeft="6dip" /> + android:paddingLeft="10dip" /> + android:paddingLeft="10dip" /> diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml index ef347da1212533eb38ff79519f55d5438462ac26..b5124904e4279fae60ca5449af78fff664222f94 100644 --- a/core/res/res/layout/search_bar.xml +++ b/core/res/res/layout/search_bar.xml @@ -21,84 +21,78 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/search_bar" android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:paddingBottom="200dip" - android:orientation="vertical" + android:layout_height="wrap_content" + android:orientation="vertical" android:focusable="true" android:descendantFocusability="afterDescendants"> - - + android:background="@drawable/search_plate_global" > + android:textColor="?android:attr/textColorPrimaryInverse" /> - - - + + android:orientation="horizontal"> + + - - - + android:dropDownVerticalOffset="-9dip" + android:popupBackground="@android:drawable/search_dropdown_background" + />

    Column Name Description
    {@link SearchManager#SUGGEST_COLUMN_TEXT_1}The application name.
    {@link SearchManager#SUGGEST_COLUMN_INTENT_COMPONENT}The component to be used when forming the intent.
    {@link SearchManager#SUGGEST_COLUMN_ICON_1}The application's icon resource id, prepended by its package name and + * separated by a colon, e.g., "com.android.alarmclock:2130837524". The + * package name is required for an activity interpreting this value to + * be able to correctly access the icon drawable, for example, in an override of + * {@link SimpleCursorAdapter#setViewImage(android.widget.ImageView, String)}.
    {@link SearchManager#SUGGEST_COLUMN_ICON_2}Unused - column provided to conform to the {@link SearchManager} stipulation + * that all providers provide either both or neither of + * {@link SearchManager#SUGGEST_COLUMN_ICON_1} and + * {@link SearchManager#SUGGEST_COLUMN_ICON_2}.
    diff --git a/docs/html/guide/appendix/faq/framework.jd b/docs/html/guide/appendix/faq/framework.jd index 76a19c56d19d83fa474d9e0f00cb92201575ec0e..33b69acf21502b27cd32a50700675732458a8bdc 100644 --- a/docs/html/guide/appendix/faq/framework.jd +++ b/docs/html/guide/appendix/faq/framework.jd @@ -12,7 +12,7 @@ parent.link=index.html from one Activity/Service to another?
  • How can I check if an Activity is already running before starting it?
  • -
  • If an Activity starts a remote service,is +
  • If an Activity starts a remote service, is there any way for the Service to pass a message back to the Activity?
  • How to avoid getting the Application not responding dialog?
  • @@ -20,7 +20,6 @@ parent.link=index.html added or removed? - @@ -32,7 +31,7 @@ default. If needed, you can declare an android:process attribute in your manifest file, to explicitly place a component (Activity/Service) in another process.

    - + @@ -47,7 +46,7 @@ separate pool of transaction threads in each process to dispatch all incoming IPC calls. The developer should create separate threads for any long-running code, to avoid blocking the main UI thread.

    - + @@ -128,7 +127,7 @@ the Data Storage for further details on how to use these components.

    - + @@ -140,7 +139,7 @@ or to bring the activity stack to the front if is already running in the background— is the to use the NEW_TASK_LAUNCH flag in the startActivity() call.

    - + @@ -156,7 +155,7 @@ messages.

    The sample code for remote service callbacks is given in ApiDemos/RemoteService

    - + @@ -166,7 +165,7 @@ href="{@docRoot}guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteSe document.

    - + @@ -194,5 +193,5 @@ removed.

    - + diff --git a/docs/html/guide/appendix/faq/troubleshooting.jd b/docs/html/guide/appendix/faq/troubleshooting.jd index 7c703e6d07f3491b5cb2f04560a3b380bbe78135..0cf1ab006d1e9e1e501de9cccec62866e905271a 100644 --- a/docs/html/guide/appendix/faq/troubleshooting.jd +++ b/docs/html/guide/appendix/faq/troubleshooting.jd @@ -23,7 +23,6 @@ parent.link=index.html
  • When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.
  • I can't install ApiDemos apps in my IDE because of a signing error
  • I can't compile my app because the build tools generated an expired debug certificate
  • -
  • I can't run a JUnit test class in Eclipse/ADT
  • ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".

    @@ -245,8 +244,8 @@ documentation.

    1. First, delete the debug keystore/key already generated by the Android build tools. Specifically, delete the debug.keystore file. On Linux/Mac OSX, the file is stored in ~/.android. On Windows XP, the file is stored in -C:\Documents and Settings\<user>\Local Settings\Application Data\Android. On Windows Vista, the file is stored in -C:\Users\<user>\AppData\Local\Android
    2. +C:\Documents and Settings\<user>\.android. On Windows Vista, the file is stored in +C:\Users\<user>\.android
    3. Next, you can either
      • Temporarily change your development machine's locale (date and time) to one that uses a Gregorian calendar, for example, United States. Once the locale is changed, use the Android build tools to compile and install your app. The build tools will regenerate a new keystore and debug key with valid dates. Once the new debug key is generated, you can reset your development machine to the original locale.
      • @@ -260,46 +259,3 @@ C:\Users\<user>\AppData\Local\Android

        For general information about signing Android applications, see Signing Your Applications.

        -

        I can't run a JUnit test class in Eclipse/ADT

        - -

        If you are developing on Eclipse/ADT, you can add JUnit test classes to your application. However, you may get an error when trying to run such a class as a JUnit test:

        - -
        Error occurred during initialization of VM
        -java/lang/NoClassDefFoundError: java/lang/ref/FinalReference
        - -

        This error occurs because android.jar does not include complete Junit.* class implementations, but includes stub classes only.

        - -

        To add a JUnit class, you have to set up a JUnit configuration:. - -

          -
        1. In the Package Explorer view, select your project.
        2. -
        3. Open the launch configuration manager. -
            -
          • In Eclipse 3.3 (Europa), select Run > - Open Run Dialog... or Run > - Open Debug Dialog... . -
          • - -
          • In Eclipse 3.4 (Ganymede), select Run > - Run Configurations... or Run > - Debug Configurations... . -
          • -
          -
        4. -
        5. In the configuration manager, right-click the "JUnit" configuration type and select New
        6. -
        7. In the new configuration's Test tab, specify the project and test class, as well as any options for running the test.
        8. -
        9. In the new configuration's Classpath tab, find "Android Library" under Bootstrap Entries and remove it.
        10. -
        11. Still in the Classpath tab, select Bootstrap Entries and click the Advanced button.
        12. -
            -
          1. Choose Add Library and click OK.
          2. -
          3. Select JRE System Library and click Next.
          4. -
          5. Select Workspace Default JRE and click Finish.
          6. -
          -
        13. Select Bootstrap Entries again and click Advanced.
        14. -
            -
          1. Choose Add Library and click OK.
          2. -
          3. Select JUnit 3 and click Finish.
          4. -
          -
        -

        When configured in this way, your JUnit test class should now run properly.

        - diff --git a/docs/html/guide/developing/app-signing.jd b/docs/html/guide/developing/app-signing.jd deleted file mode 100644 index 582dfb267b6faaebf437431f12201b844ce6be37..0000000000000000000000000000000000000000 --- a/docs/html/guide/developing/app-signing.jd +++ /dev/null @@ -1,428 +0,0 @@ -page.title=Signing Your Applications -@jd:body - -

        The Android system requires that all installed applications be digitally -signed with a certificate whose private key is held by the application's -developer. The system uses the certificate as a means of identifying the author of -an application and establishing trust relationships between applications, rather -than for controlling which applications the user can install. The certificate -does not need to be signed by a certificate authority: it is perfectly -allowable, and typical, for Android applications to use self-signed -certificates.

        - -

        The important points to understand about signing Android applications are:

        - -
          -
        • All applications must be signed. The system will not install an application -that is not signed.
        • -
        • You can use self-signed certificates to sign your applications. No certificate authority -is needed.
        • -
        • When you are ready to publish your application, you must sign it with a suitable private -key. You can not publish an application that is signed with the default key generated -by the SDK tools. -
        • -
        • The system tests a signer certificate's expiration date only at install time. If an -application's signer certificate expires after the application is installed, the application -will continue to function normally.
        • -
        • You can use standard tools — Keytool and Jarsigner — to generate keys and -sign your application .apk files.
        • -
        - -

        The Android system will not install or run an application that is not signed appropriately. This -applies wherever the Android system is run, whether on an actual device or on the emulator. -For this reason, you must set up signing for your application before you will be able to -run or debug it on an emulator or device.

        - -

        The Android SDK tools assist you in signing your applications when debugging. Both the ADT Plugin -for Eclipse and the Ant build tool offer two signing modes — debug mode and release mode. - -

          -
        • In debug mode, the build tools use the Keytool utility, included in the JDK, to create -a keystore and key with a known alias and password. At each compilation, the tools then use -the debug key to sign the application .apk file. Because the password is known, the tools -don't need to prompt you for the keystore/key password each time you compile.
        • - -
        • When your application is ready for release, you compile it in release signing mode. -In this mode, the tools compile your .apk without signing it. You must then sign -the .apk manually — with your private key — -using Jarsigner (or similar tool). If you do not have a suitable private key already, -you can run Keytool manually to generate your own keystore/key and then sign your -application with Jarsigner.
        • -
        - -

        Signing Strategies

        - -

        Some aspects of application signing may affect how you approach the development -of your application, especially if you are planning to release multiple -applications.

        - -

        In general, the recommended strategy for all developers is to sign -all of your applications with the same certificate, throughout the expected -lifespan of your applications. There are several reasons why you should do so:

        - -
          -
        • Application upgrade — As you release upgrades to your -application, you will want to sign the upgrades with the same certificate, if you -want users to upgrade seamlessly to the new version. When the system is -installing an update to an application, if any of the certificates in the -new version match any of the certificates in the old version, then the -system allows the update. If you sign the version without using a matching -certificate, you will also need to assign a different package name to the -application — in this case, the user installs the new version as a -completely new application. - -
        • Application modularity — The Android system allows applications that -are signed by the same certificate to run in the same process, if the -applications so request, so that the system treats them as a single application. -In this way you can deploy your application in modules, and users can update -each of the modules independently if needed.
        • - -
        • Code/data sharing through permissions — The Android system provides -signature-based permissions enforcement, so that an application can expose -functionality to another application that is signed with a specified -certificate. By signing multiple applications with the same certificate and -using signature-based permissions checks, your applications can share code and -data in a secure manner.
        • - - - -
        - -

        Another important consideration in determining your signing strategy is -how to set the validity period of the key that you will use to sign your -applications.

        - -
          -
        • If you plan to support upgrades for a single application, you should ensure -that your key has a validity period that exceeds the expected lifespan of -that application. A validity period of 25 years or more is recommended. -When your key's validity period expires, users will no longer be -able to seamlessly upgrade to new versions of your application.
        • - -
        • If you will sign multiple distinct applications with the same key, -you should ensure that your key's validity period exceeds the expected -lifespan of all versions of all of the applications, including -dependent applications that may be added to the suite in the future.
        • - -
        • If you plan to publish your application(s) on Android Market, the -key you use to sign the application(s) must have a validity period -ending after 22 October 2033. The Market server enforces this requirement -to ensure that users can seamlessly upgrade Market applications when -new versions are available.
        • -
        - -

        As you design your application, keep these points in mind and make sure to -use a suitable certificate to sign your applications.

        - -

        Basic Setup for Signing

        - -

        To support the generation of a keystore and debug key, you should first make sure that -Keytool is available to the SDK build -tools. In most cases, you can tell the SDK build tools how to find Keytool by making sure -that your JAVA_HOME environment variable is set and that it references a suitable JDK. -Alternatively, you can add the JDK version of Keytool to your PATH variable.

        - -

        If you are developing on a version of Linux that originally came with GNU Compiler for -Java, make sure that the system is using the JDK version of Keytool, rather than the gcj -version. If Keytool is already in your PATH, it might be pointing to a symlink at -/usr/bin/keytool. In this case, check the symlink target to make sure that it points -to the Keytool in the JDK.

        - -

        If you will release your application to the public, you will also need to have -the Jarsigner tool available on your machine. Both Jarsigner and Keytool are included -in the JDK.

        - -

        Signing in Debug Mode

        - -

        The Android build tools provide a debug signing mode that makes it easier for you -to develop and debug your application, while still meeting the Android system -requirement for signing your .apk when it is installed in the emulator or a device.

        - -

        If you are developing in Eclipse/ADT and have set up Keytool as described -above, signing in debug mode is enabled by default. When you run or debug your -application, ADT signs the .apk for you and installs it on the emulator. No -specific action on your part is needed, provided ADT has access to Keytool.

        - -

        If you use Ant to build your .apk files, debug signing mode -is enabled by default, assuming that you are using a build.xml file generated by the -activitycreator tool included in the latest SDK. When you run Ant against build.xml to -compile your app, the build script generates a keystore/key and signs the .apk for you. -No specific action on your part is needed.

        - -

        Note that you can not release your application to the public if it is signed only with -the debug key.

        - -

        Signing for Public Release

        - -

        When your application is ready for release to other users, you must:

        -
          -
        1. Compile the application in release mode
        2. -
        3. Obtain a suitable private key, and then
        4. -
        5. Sign the application with your private key
        6. -
        7. Secure your private key
        8. -
        - -

        The sections below provide information about these steps.

        - -

        Compiling for Release

        - -

        To prepare your application for release, you must first compile it in release mode. -In release mode, the Android build tools compile your application as usual, -but without signing it with the debug key.

        - -

        If you are developing in Eclipse/ADT, right-click the project in the Package -pane and select Android Tools > Export Application -Package. You can then specify the file location for the unsigned .apk. -Alternatively, you can follow the "Exporting the unsigned .apk" -link in the Manifest Editor overview page.

        - -

        If you are using Ant, all you need to do is specify the build target -"release" in the Ant command. For example, if you are running Ant from the -directory containing your build.xml file, the command would look like this:

        - -
        $ ant release
        - -

        The build script compiles the application .apk without signing it. - -

        Note that you can not release your application unsigned, or signed with the debug key.

        - -

        Obtaining a Suitable Private Key

        - -

        In preparation for signing your application, you must first ensure that -you have a suitable private key with which to sign. A suitable private -key is one that:

        - -
          -
        • Is in your possession
        • -
        • Represents the personal, corporate, or organizational entity to be identified -with the application
        • -
        • Has a validity period that exceeds the expected lifespan of the application -or application suite. A validity period of more than 25 years is recommended. -

          If you plan to publish your application(s) on Android Market, note that a -validity period ending after 22 October 2033 is a requirement. You can not upload an -application if it is signed with a key whose validity expires before that date. -

        • -
        • Is not the debug key generated by the Android SDK tools.
        • -
        - -

        The key may be self-signed. If you do not have a suitable key, you must -generate one using Keytool. Make sure that you have Keytool available, as described -in Basic Setup.

        - -

        To generate a self-signed key with Keytool, use the keytool -command and pass any of the options listed below (and any others, as -needed).

        - -

        Before you run Keytool, make sure to read Securing Your Key for a discussion of how to keep your -key secure and why doing so is critically important to you and to users. In -particular, when you are generating your key, you should select strong -passwords for both the keystore and key.

        - -
    MyApp/
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Keytool OptionDescription
    -genkeyGenerate a key pair (public and private -keys)
    -vEnable verbose output.
    -keystore <keystore-name>.keystoreA name -for the keystore containing the private key.
    -storepass <password>

    A password for the -keystore.

    As a security precaution, do not include this option -in your command line unless you are working at a secure computer. -If not supplied, Keytool prompts you to enter the password. In this -way, your password is not stored in your shell history.

    -alias <alias_name>An alias for the key.
    -keyalg <alg>The encryption algorithm to use -when generating the key.
    -dname <name>

    A Distinguished Name that describes -who created the key. The value is used as the issuer and subject fields in the -self-signed certificate.

    Note that you do not need to specify this option -in the command line. If not supplied, Jarsigner prompts you to enter each -of the Distinguished Name fields (CN, OU, and so on).

    -validity <valdays>

    The validity period for the -key, in days.

    Note: A value of 9500 or greater is recommended.

    -keypass <password>

    The password for the key.

    -

    As a security precaution, do not include this option -in your command line unless you are working at a secure computer. -If not supplied, Keytool prompts you to enter the password. In this -way, your password is not stored in your shell history.

    - - -

    Here's an example of a Keytool command that generates a private key:

    - -
    $ keytool -genkey -v -keystore my-release-key.keystore 
    --alias alias_name -keyalg RSA -validity 9500
    - -

    Running the example command above, Keytool prompts you to provide -passwords for the keystore and key, and to provide the Distinguished -Name fields for your key. It then generates the keystore as a file called -my-release-key.keystore. The keystore and key are -protected by the passwords you entered. The keystore contains -a single key, valid for 9500 days. The alias is a name that you — -will use later, to refer to this keystore when signing your application.

    - -

    For more information about Keytool, see the documentation at - -http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security

    - -

    Signing Your Application

    - -

    When you are ready to actually sign your .apk for release, you can do so -using the Jarsigner tool. Make sure that you have Jarsigner available on your -machine, as described in Basic Setup. Also, make sure that -the keystore containing your private key is available.

    - -

    To sign your application, you run Jarsigner, referencing both the -application's .apk and the keystore containing the private key with which to -sign the .apk. The table below shows the options you could use.

    - - - - - - - - - - - - - - - - - - -
    Jarsigner OptionDescription
    -keystore <keystore-name>.keystoreThe name of -the keystore containing your private key.
    -verboseEnable verbose output.
    -storepass <password>

    The password for the -keystore.

    As a security precaution, do not include this option -in your command line unless you are working at a secure computer. -If not supplied, Jarsigner prompts you to enter the password. In this -way, your password is not stored in your shell history.

    -keypass <password>

    The password for the private -key.

    As a security precaution, do not include this option -in your command line unless you are working at a secure computer. -If not supplied, Jarsigner prompts you to enter the password. In this -way, your password is not stored in your shell history.

    - -

    Here's how you would use Jarsigner to sign an application package called -my_application.apk, using the example keystore created above. -

    - -
    $ jarsigner -verbose -keystore my-release-key.keystore 
    -my_application.apk alias_name
    - -

    Running the example command above, Jarsigner prompts you to provide -passwords for the keystore and key. It then modifies the APK -in-place, meaning the .apk is now signed. Note that you can sign an -APK multiple times with different keys.

    - -

    To verify that your .apk is signed, you can use a command like this:

    - -
    $ jarsigner -verify my_signed.apk
    - -

    If the .apk is signed properly, Jarsigner prints "jar verified". -If you want more details, you can try one of these commands:

    - -
    $ jarsigner -verify -verbose my_application.apk
    - -

    or

    - -
    $ jarsigner -verify -verbose -certs my_application.apk
    - -

    The command above, with the -certs option added, will show you the -"CN=" line that describes who created the key.

    - -

    Note: if you see "CN=Android Debug", this means the .apk was -signed with the debug key generated by the Android SDK. If you intend to release -your application, you must sign it with your private key instead of the debug -key.

    - -

    For more information about Jarsigner, see the documentation at - -http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security

    - -

    Securing Your Private Key

    - -

    Maintaining the security of your private key is of critical importance, both -to you and to the user. If you allow someone to use your key, or if you leave -your keystore and passwords in an unsecured location such that a third-party -could find and use them, your authoring identity and the trust of the user -are compromised.

    - -

    If a third party should manage to take your key without your knowledge or -permission, that person could sign and distribute applications that maliciously -replace your authentic applications or corrupt them. Such a person could also -sign and distribute applications under your identity that attack other -applications or the system itself, or corrupt or steal user data.

    - -

    Your reputation as a developer entity depends on your securing your private -key properly, at all times, until the key is expired. Here are some tips for -keeping your key secure:

    - -
      -
    • Select strong passwords for the keystore and key.
    • -
    • When you generate your key with Keytool, do not supply the --storepass and -keypass options at the command line. -If you do so, your passwords will be available in your shell history, -which any user on your computer could access.
    • -
    • Similarly, when signing your applications with Jarsigner, -do not supply the -storepass and -keypass -options at the command line.
    • -
    • Do not give or lend anyone your private key, and do not let unauthorized -persons know your keystore and key passwords.
    • -
    - -

    In general, if you follow common-sense precautions when generating, using, -and storing your key, it will remain secure.

    - -

    Expiry of the Debug Certificate

    - -

    The self-signed certificate used to sign your application in debug mode (the default on -Eclipse/ADT and Ant builds) will have an expiration date of 365 days from its creation date.

    - -

    When the certificate expires, you will get a build error. On Ant builds, the error -looks like this:

    - -
    debug:
    -[echo] Packaging bin/samples-debug.apk, and signing it with a debug key...
    -[exec] Debug Certificate expired on 8/4/08 3:43 PM
    - -

    In Eclipse/ADT, you will see a similar error in the Android console.

    - -

    To fix this problem, simply delete the debug.keystore file. On Linux/Mac OSX, -the file is stored in ~/.android. OOn Windows XP, the file is stored in -C:\Documents and Settings\<user>\Local Settings\Application Data\Android. -On Windows Vista, the file is stored in -C:\Users\<user>\AppData\Local\Android.

    - -

    The next time you build, the build tools will regenerate a new keystore and debug key.

    - -

    Note that, if your development machine is using a non-Gregorian locale, the build -tools may erroneously generate an already-expired debug certificate, so that you get an -error when trying to compile your application. For workaround information, see the -troubleshooting topic -I can't compile my app because the build tools generated an expired debug -certificate.

    \ No newline at end of file diff --git a/docs/html/guide/developing/eclipse-adt.jd b/docs/html/guide/developing/eclipse-adt.jd index 8c482ee40ce57992e07de63fefec5100533df969..75f3d78f48097a96349ea4987a4d6fa228797124 100644 --- a/docs/html/guide/developing/eclipse-adt.jd +++ b/docs/html/guide/developing/eclipse-adt.jd @@ -1,193 +1,393 @@ -page.title=In Eclipse, with ADT +page.title=Developing In Eclipse, with ADT @jd:body -

    The Android Development Tools (ADT) plugin for Eclipse adds powerful extensions to the Eclipse integrated development environment. It allows you to create and debug Android applications easier and faster. If you use Eclipse, the ADT plugin gives you an incredible boost in developing Android applications:

    + + + +

    The Android Development Tools (ADT) plugin for Eclipse adds powerful extensions to the Eclipse +integrated development environment. It allows you to create and debug Android applications easier +and faster. If you use Eclipse, the ADT plugin gives you an incredible boost in developing Android +applications:

      -
    • It gives you access to other Android development tools from inside the Eclipse IDE. For example, ADT lets you access the many capabilities of the DDMS tool: take screenshots, manage port-forwarding, set breakpoints, and view thread and process informationd irectly from Eclipse.
    • -
    • It provides a New Project Wizard, which helps you quickly create and set up all of the basic files you'll need for a new Android application.
    • +
    • It gives you access to other Android development tools from inside the Eclipse IDE. For +example, ADT lets you access the many capabilities of the DDMS tool: take screenshots, manage +port-forwarding, set breakpoints, and view thread and process informationd irectly from Eclipse.
    • +
    • It provides a New Project Wizard, which helps you quickly create and set up all of the +basic files you'll need for a new Android application.
    • It automates and simplifies the process of building your Android application.
    • -
    • It provides an Android code editor that helps you write valid XML for your Android manifest and resource files.
    • +
    • It provides an Android code editor that helps you write valid XML for your Android +manifest and resource files.
    • +
    • It will even export your project into a signed APK, which can be distributed to users.
    -

    To begin developing Android applications in the Eclipse IDE with ADT, you first need to download the Eclipse IDE and then download and install the ADT plugin. To do so, follow the steps given in Installing the ADT Plugin, in the installation documentation included with your SDK package.

    - -

    Once you've installed the ADT plugin, you begin by creating an Android -project and then set up a launch configuration. After that, you can write, run, and debug -your application.

    +

    To begin developing Android applications in the Eclipse IDE with ADT, you first need to +download the Eclipse IDE and then download and install the ADT plugin. To do so, follow the +steps given in Installing +the ADT Plugin.

    -

    The sections below provide instructions assuming that you have installed the ADT plugin -in your Eclipse environment. If you haven't installed the ADT plugin, you should do that -before using the instructions below.

    +

    If you are already developing applications using a version of ADT earlier than 0.9, make +sure to upgrade to the latest version before continuing. See the guide to +Update Your Eclipse ADT Plugin.

    - +

    Note: This guide assumes you are using the latest version of +the ADT plugin (0.9). While most of the information covered also applies to previous +versions, if you are using an older version, you may want to consult this document from +the set of documentation included in your SDK package (instead of the online version).

    -

    Creating an Android Project

    -

    The ADT plugin provides a New Project Wizard that you can use to quickly create an -Eclipse project for new or existing code. To create the project, follow these steps:

    +

    Creating an Android Project

    - +

    The ADT plugin provides a New Project Wizard that you can use to quickly create a new +Android project (or a project from existing code). To create a new project:

      -
    1. Select File > New > Project
    2. -
    3. Select Android > Android Project, and press Next
    4. -
    5. Select the contents for the project: -
        -
      • Select Create new project in workspace to start a project for new code. -

        Enter the project name, the base package name, the name of a single Activity class to create as a stub .java file, and a name to use for your application.

      • -
      • Select Create project from existing source to start a project from existing code. Use this option if you want to build and run any of the sample applications included with the SDK. The sample applications are located in the samples/ directory in the SDK. -

        Browse to the directory containing the existing source code and click OK. If the directory contains a valid Android manifest file, the ADT plugin fills in the package, activity, and application names for you.

        -
      • -
      -
    6. -
    7. Press Finish.
    8. -
    - -

    The ADT plugin creates the these folders and - files for you as appropriate for the type of project:

    - +
  • Select File > New > Project.
  • +
  • Select Android > Android Project, and click + Next.
  • +
  • Select the contents for the project: +
      +
    • Enter a Project Name. This will be the name of the folder where your + project is created.
    • +
    • Under Contents, select Create new project in workspace. + Select your project workspace location.
    • +
    • Under Target, select an Android target to be used as the project's Build Target. + The Build Target + specifies which Android platform you'd like your application built against. +

      Unless you know that you'll be using new APIs introduced in the latest SDK, you should + select a target with the lowest platform version possible, such as Android 1.1.

      +

      Note: You can change your the Build Target for your + project at any time: Right-click the project in the Package Explorer, select + Properties, select Android and then check + the desired Project Target.

      +
    • +
    • Under Properties, fill in all necessary fields.
        -
      • src/   A - folder that includes your stub .java Activity file.
      • -
      • res/   A folder for your - resources.
      • -
      • AndroidManifest.xml   The - manifest for your project.
      • +
      • Enter an Application name. This is the human-readable title for your + application — the name that will appear on the Android device.
      • +
      • Enter a Package name. This is the package namespace (following the same rules + as for packages in the Java programming language) where all your source code + will reside.
      • +
      • Select Create Activity (optional, of course, but common) and enter a name + for your main Activity class.
      • +
      • Enter a Min SDK Version. This is an integer that indicates + the minimum API Level required to properly run your application. + Entering this here automatically sets the minSdkVersion attribute in the + <uses-sdk> + of your Android Manifest file. If you're unsure of the appropriate API Level to use, + copy the API Level listed for the Build Target you selected in the Target tab.
      - +
    • +
    +
  • +
  • Click Finish.
  • - +

    Tip: +You can also start the New Project Wizard from the New icon in the toolbar.

    + +

    Once you complete the New Project Wizard, ADT creates the following +folders and files in your new project:

    +
    +
    src/
    +
    Includes your stub Activity Java file. All other Java files for your application + go here.
    +
    <Android Version>/ (e.g., Android 1.1/)
    +
    Includes the android.jar file that your application will build against. + This is determined by the build target that you have chosen in the New Project + Wizard.
    +
    gen/
    +
    This contains the Java files generated by ADT, such as your R.java file + and interfaces created from AIDL files.
    +
    assets/
    +
    This is empty. You can use it to store raw asset files. See + Resources and Assets.
    +
    res/
    +
    A folder for your application resources, such as drawable files, layout files, string + values, etc. See + Resources and Assets.
    +
    AndroidManifest.xml
    +
    The Android Manifest for your project. See + The AndroidManifest.xml + File.
    +
    default.properties
    +
    This file contains project settings, such as the build target. This files is integral + to the project, as such, it should be maintained in a Source Revision Control system. + It should never be edited manually — to edit project properties, + right-click the project folder and select "Properties".
    +
    + + +

    Running Your Application

    + +

    Wait! Before you can run your application on the Android Emulator, +you must create an Android Virtual Device (AVD). +An AVD is a configuration that specifies the Android platform to be used on the emulator. +You can read more about AVDs in the Developing +Overview, but if you just want to get started, follow the simple guide below to create +an AVD.

    + +

    If you will be running your applications only on actual device hardware, you do not +need an AVD — see +Developing On a Device for information +on running your applicaiton.

    + +

    Creating an AVD

    + +

    To avoid some explanation that's beyond the scope of this document, here's the +basic procedure to create an AVD:

    -

    Creating a Launch Configuration

    +
      +
    1. Open a command-line (e.g.,"Command Prompt" application on Windows, or "Terminal" + on Mac/Linux) and navigate to your SDK package's + tools/ directory.
    2. +
    3. First, you need to select a Deployment Target. To view available targets, execute: +
      android list targets
      +

      This will output a list of available Android targets, such as:

      +
      +id:1
      +    Name: Android 1.1
      +    Type: platform
      +    API level: 2
      +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
      +id:2
      +    Name: Android 1.5
      +    Type: platform
      +    API level: 3
      +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
      +
      +

      Find the target that matches the Android platform upon which you'd like + to run your application. Note the integer value of the id — + you'll use this in the next step.

      +
    4. +
    5. Create a new AVD using your selected Deployment Target. Execute: +
      android create avd --name <your_avd_name> --target <targetID>
      +
    6. Next, you'll be asked whether you'd like to create a custom hardware profile. + If you respond "yes," you'll be presented with a series of prompts to define various aspects of the + device hardware (leave entries blank to use default values, which are shown in brackets). Otherwise, + press return to use all default values ("no" is the default).
    7. + +
    -

    Before you can run and debug your application in Eclipse, you must create a launch configuration for it. A launch configuration specifies the project to launch, the Activity to start, the emulator options to use, and so on.

    +

    That's it; your AVD is ready. In the next section, you'll see how the AVD is used +when launching your application on an emulator.

    -

    To create a launch configuration for the application, follow these steps as appropriate for your Eclipse version:

    +

    To learn more about creating and managing AVDs, please read the +Android Virtual Devices +documentation.

    -
      -
    1. Open the launch configuration manager. -
        -
      • In Eclipse 3.3 (Europa), select Run > - Open Run Dialog... or Run > - Open Debug Dialog... as appropriate. -
      • -
      • In Eclipse 3.4 (Ganymede), select Run > - Run Configurations... or Run > - Debug Configurations... as appropriate. -
      • -
      -
    2. -
    3. In the project type list on the left, locate the Android Application item and double-click it (or right-click > New), to create a new launch configuration.
    4. -
    5. Enter a name for your configuration.
    6. -
    7. On the Android tab, browse for the project and Activity to start.
    8. -
    9. On the Target tab, set the desired screen and network properties, as well as any other emulator startup options.
    10. -
    11. You can set additional options on the Common tab as desired.
    12. -
    13. Press Apply to save the launch configuration, or press Run or Debug (as appropriate).
    14. +

      Running your application

      -
    +

    Note: Before you can run your application, be sure that +you have created an AVD with a target that satisfies your application's Build Target. +If an AVD cannot be found that meets the requirements of your Build Target, you will see +a console error telling you so and the launch will be aborted.

    +

    To run (or debug) your application, select Run > Run (or +Run > Debug) from the Eclipse main menu. The ADT plugin +will automatically create a default launch configuration for the project.

    -

    Setting Up Application Signing

    +

    When you choose to run or debug your application, Eclipse will perform the following:

    -

    As you begin developing Android applications, you should understand that all -Android applications must be digitally signed before the system will install -them on the emulator or an actual device.

    +
      +
    1. Compile the project (if there have been changes since the last build).
    2. +
    3. Create a default launch configuration (if one does not already exist for the project).
    4. +
    5. Install and start the application on an emulator or device (based on the Deployment Target + defined by the run configuration). +

      By default, Android application run configurations use an "automatic target" mode for + selecting a device target. For information on how automatic target mode selects a + deployment target, see Automatic and manual + target modes below.

      +
    6. +
    -

    The ADT plugin helps you get started quickly by signing your .apk files with -a debug key, prior to installing them on the emulator. This means that you can -compile your application and install it on the emulator without having to -generate your own private key. However, please note that if you intend to -publish your application, you must sign the application with your own -private key, rather than the debug key generated by the SDK tools.

    +

    If debugging, the application will start in the "Waiting For Debugger" mode. Once the +debugger is attached, Eclipse will open the Debug perspective.

    + +

    To set or change the launch configuration used for your project, use the launch configuration manager. +See Creating a Launch Configuration for information.

    -

    To sign your applications, the ADT plugin requires the Keytool utility -included in the JDK. To set up your development environment for -signing, you need to make sure that Keytool is available on your -machine that the ADT plugin knows how to find it.

    -

    In most cases, you can tell the SDK build tools how to find Keytool by making -sure that your JAVA_HOME environment variable is set and that it references a -suitable JDK. Alternatively, you can add the JDK version of Keytool to your -PATH variable.

    +

    Creating a Run Configuration

    -

    If you are developing on a version of Linux that originally came with Gnu -Compiler for Java, make sure that the system is using the JDK version of -Keytool, rather than the gcj version. If keytool is already in your PATH, it -might be pointing to a symlink at /usr/bin/keytool. In this case, check the -symlink target to make sure that it points to the keytool in the JDK.

    +

    The run configuration specifies the project to run, the Activity +to start, the emulator options to use, and so on. When you first run a project +as an Android Application, ADT will automatically create a run configuration. +The default run configuration will +launch the default project Activity and use automatic target mode for device selection +(with no preferred AVD). If the default setting don't suit your project, you can +customize the launch configuration or even create a new.

    -

    In all cases, please read and understand Signing Your -Applications, which provides an overview of application signing on Android -and what it means to you as an Android application developer.

    +

    To create or modify a launch configuration, follow these steps as appropriate +for your Eclipse version:

    +
      +
    1. Open the run configuration manager. +
        +
      • In Eclipse 3.3 (Europa), select Run > + Open Run Dialog (or Open Debug Dialog) +
      • +
      • In Eclipse 3.4 (Ganymede), select Run > + Run Configurations (or + Debug Configurations) +
      • +
      +
    2. +
    3. Expand the Android Application item and create a new + configuration or open an existing one. +
        +
      • To create a new configuration: +
          +
        1. Select Android Application and click the New launch configuration + icon above the list (or, right-click Android Application and click + New).
        2. +
        3. Enter a Name for your configuration.
        4. +
        5. In the Android tab, browse and select the project you'd like to run with the + configuration.
        6. +
        +
      • To open an existing configuration, select the configuration name from the list + nested below Android Application.
      • +
      +
    4. +
    5. Adjust your desired launch configuration settings. +

      In the Target tab, consider whether you'd like to use Manual or Automatic mode + when selecting an AVD to run your application. + See the following section on Automatic and manual target + modes).

      +
    6. +
    - -

    Running and Debugging an Application

    +

    Automatic and manual target modes

    -

    Once you've set up the project and launch configuration for your application, you can run or debug it as described below.

    +

    By default, a run configuration uses the automatic target mode in order to select +an AVD. In this mode, ADT will select an AVD for the application in the following manner:

    -From the Eclipse main menu, select Run > Run or Run > Debug as appropriate, to run or debug the active launch configuration.
  • +
      +
    1. If there's a device or emulator already running and its AVD configuration + meets the requirements of the application's build target, the application is installed + and run upon it.
    2. +
    3. If there's more than one device or emulator running, each of which meets the requirements + of the build target, a "device chooser" is shown to let you select which device to use.
    4. +
    5. If there are no devices or emulators running that meet the requirements of the build target, + ADT looks at the available AVDs. If one meets the requirements of the build target, + the AVD is used to launch a new emulator, upon which the application is installed and run.
    6. +
    7. If all else fails, the application will not be run and you will see a console error warning + you that there is no existing AVD that meets the build target requirements.
    8. +
    -

    Note that the active launch configuration is the one most recently selected in the Run configuration manager. It does not necessarily correspond to the application that is selected in the Eclipse Navigation pane (if any).

    +

    However, if a "preferred AVD" is selected in the run configuration, then the application +will always be deployed to that AVD. If it's not already running, then a new emulator +will be launched.

    -

    To set or change the active launch configuration, use the launch configuration manager. See Creating a Launch Configuration for information about how to access the launch configuration manager..

    +

    If your run configuration uses manual mode, then the "device chooser" +is presented every time that your application is run, so that you can select which AVD to use.

    -

    Running or debugging the application triggers these actions:

    -
    • Starts the emulator, if it is not already running.
    • -
    • Compiles the project, if there have been changes since the last build, and installs the application on the emulator.
    • -
    • Run starts the application.
    • -
    • Debug starts the application in "Wait for debugger" mode, then opens the Debug perspective and attaches the Eclipse Java debugger to the application.
    • -
    +

    Signing your Applications

    +

    As you begin developing Android applications, understand that all +Android applications must be digitally signed before the system will install +them on an emulator or an actual device. There are two ways to do this: +with a debug key (for immediate testing on an emulator or development device) +or with a private key (for application distribution).

    -

    Eclipse Tips

    -

    Executing arbitrary Java expressions in Eclipse

    -

    You can execute arbitrary code when paused at a breakpoint in Eclipse. For example, - when in a function with a String argument called "zip", you can get - information about packages and call class methods. You can also invoke arbitrary - static methods: for example, entering android.os.Debug.startMethodTracing() will - start dmTrace.

    -

    Open a code execution window, select Window>Show - View>Display from the main menu to open the - Display window, a simple text editor. Type your expression, highlight the - text, and click the 'J' icon (or CTRL + SHIFT + D) to run your - code. The code runs in the context of the selected thread, which must be - stopped at a breakpoint or single-step point. (If you suspend the thread - manually, you have to single-step once; this doesn't work if the thread is - in Object.wait().)

    -

    If you are currently paused on a breakpoint, you can simply highlight and execute - a piece of source code by pressing CTRL + SHIFT + D.

    -

    You can highlight a block of text within the same scope by pressing ALT +SHIFT - + UP ARROW to select larger and larger enclosing blocks, or DOWN ARROW to select - smaller blocks.

    -

    Here are a few sample inputs and responses in Eclipse using the Display window.

    - - - - - - - - - - - - - - - - - -
    InputResponse
    zip(java.lang.String) /work/device/out/linux-x86-debug/android/app/android_sdk.zip
    zip.endsWith(".zip")(boolean) true
    zip.endsWith(".jar")(boolean) false
    -

    You can also execute arbitrary code when not debugging by using a scrapbook page. - Search the Eclipse documentation for "scrapbook".

    - -

    Running DDMS Manually

    - -

    Although the recommended way to debug is to use the ADT plugin, you can manually run DDMS and configure Eclipse to debug on port 8700. (Note: Be sure that you have first started DDMS).

    +

    The ADT plugin helps you get started quickly by signing your .apk files with +a debug key, prior to installing them on an emulator or development device. This means that you can +quickly run your application from Eclipse without having to +generate your own private key. No specific action on your part is needed, +provided ADT has access to Keytool.However, please note that if you intend +to publish your application, you must sign the application with your +own private key, rather than the debug key generated by the SDK tools.

    + +

    Please read Signing Your +Applications, which provides a thorough guide to application signing on Android +and what it means to you as an Android application developer. The document also includes +a guide to exporting and signing your application with the ADT's Export Wizard.

    + + +

    Eclipse Tips

    + +

    Executing arbitrary Java expressions in Eclipse

    + +

    You can execute arbitrary code when paused at a breakpoint in Eclipse. For example, + when in a function with a String argument called "zip", you can get + information about packages and call class methods. You can also invoke arbitrary + static methods: for example, entering android.os.Debug.startMethodTracing() will + start dmTrace.

    +

    Open a code execution window, select Window>Show + View>Display from the main menu to open the + Display window, a simple text editor. Type your expression, highlight the + text, and click the 'J' icon (or CTRL + SHIFT + D) to run your + code. The code runs in the context of the selected thread, which must be + stopped at a breakpoint or single-step point. (If you suspend the thread + manually, you have to single-step once; this doesn't work if the thread is + in Object.wait().)

    +

    If you are currently paused on a breakpoint, you can simply highlight and execute + a piece of source code by pressing CTRL + SHIFT + D.

    +

    You can highlight a block of text within the same scope by pressing ALT +SHIFT + + UP ARROW to select larger and larger enclosing blocks, or DOWN ARROW to select + smaller blocks.

    +

    Here are a few sample inputs and responses in Eclipse using the Display window.

    + + + + + + + + + + + + + + + + + + +
    InputResponse
    zip(java.lang.String) + /work/device/out/linux-x86-debug/android/app/android_sdk.zip
    zip.endsWith(".zip")(boolean) true
    zip.endsWith(".jar")(boolean) false
    +

    You can also execute arbitrary code when not debugging by using a scrapbook page. + Search the Eclipse documentation for "scrapbook".

    + + +

    Running DDMS Manually

    + +

    Although the recommended way to debug is to use the ADT plugin, you can manually run +DDMS and configure Eclipse to debug on port 8700. (Note: Be sure that you +have first started DDMS).

    + + + diff --git a/docs/html/guide/developing/other-ide.jd b/docs/html/guide/developing/other-ide.jd index 7bcb509a4f4eee5ea10d335e32810d88891397ff..8cdf0b91d7b80e4a807b2a7f90fb246323787a98 100644 --- a/docs/html/guide/developing/other-ide.jd +++ b/docs/html/guide/developing/other-ide.jd @@ -1,167 +1,408 @@ -page.title=In Other IDEs +page.title=Developing In Other IDEs @jd:body + +

    The recommended way to develop an Android application is to use - Eclipse with the Android - Development Tools (ADT) plugin, provided in the SDK. The ADT plugin - provides editing, building,and debugging functionality integrated right into the IDE.

    +Eclipse with the ADT plugin. +The ADT plugin provides editing, building, debugging, and .apk packaging and signing functionality +integrated right into the IDE.

    -

    However, if you'd rather develop your application in another IDE, such as IntelliJ, - or use Eclipse without the ADT plugin, you can do that instead. The SDK - provides the tools you need to set up, build, and debug your application. -

    +

    However, if you'd rather develop your application in another IDE, such as IntelliJ, +or in a basic editor, such as Emacs, you can do that instead. The SDK +includes all the tools you need to set up an Android project, build it, debug it and then +package it for distribution. This document is your guide to using these tools.

    -

    Creating an Android Project

    +

    Essential Tools

    -

    The Android SDK includes activityCreator, a program that generates a number of stub files for your project, as well as a build file. You can use the program to create an Android project for new code or from existing code, such as the sample applications included in the SDK. For Linux and Mac, the SDK provides activitycreator and for Windows, activityCreator.bat, a batch script. Regardless of platform, you can use activitycreator in the same way.

    +

    When developing in IDEs or editors other than Eclipse, you'll require +familiarity with the following Android SDK tools:

    -

    To run activityCreator and create an Android project, follow these steps:

    +
    +
    android
    +
    To create/update Android projects and to create/move/delete AVDs.
    +
    Android Emulator
    +
    To run your Android applications on an emulated Android platform.
    +
    Android Debug Bridge
    +
    To interface with your emulator or connected device (install apps, + shell the device, issue commands, etc.). +
    +
    + +

    In addition to the above tools, included with the SDK, you'll use the following +open source and third-party tools:

    + +
    +
    Ant
    +
    To compile and build your Android project into an installable .apk file.
    +
    Keytool
    +
    To generate a keystore and private key, used to sign your .apk file.
    +
    Jarsigner (or similar signing tool)
    +
    To sign your .apk file with a private key generated by keytool.
    +
    + +

    In the topics that follow, you'll be introduced to each of these tools as necessary. +For more advanced operations, please read the respective documentation for each tool.

    + + +

    Creating an Android Project

    + +

    To create an Android project, you must use the android tool. When you create +a new project with android, it will generate a project directory +with some default application files, stub files, configuration files and a build file.

    -
      -
    1. In the command line, change to the tools/ directory of the SDK and create a new directory for your project files. If you are creating a project from existing code, change to the root folder of your application instead.
    2. -
    3. Run activityCreator. In the command, you must specify a fully-qualified class name as an argument. If you are creating a project for new code, the class represents the name of a stub class that the script will create. If you are creating a project from existing code, you must specify the name of one Activity class in the package. Command options for the script include: +

      Creating a new Project

      + +

      If you're starting a new project, use the android create project +command to generate all the necessary files and folders.

      + +

      To create a new Android project, open a command-line, +navigate to the tools/ directory of your SDK and run:

      +
      +android create project \
      +--target <targetID> \
      +--path /path/to/your/project \
      +--activity <your_activity_name> \
      +--package <your_package_namespace>
      +
      +
        -
      • --out <folder> which sets the output directory. By default, the output directory is the current directory. If you created a new directory for your project files, use this option to point to it.
      • -
      • --ide intellij, which generates IntelliJ IDEA project files in the newly created project
      • +
      • target is the "build target" for your application. It corresponds + to an Android platform library (including any add-ons, such as Google APIs) that you would like to + build your project against. To see a list of available targets and their corresponding IDs, + execute: android list targets.
      • +
      • path is the location of your project directory. If the directory does not exist, + it will be created for you.
      • +
      • activity is the name for your {@link android.app.Activity} class. This class file + will be created for you inside + <path_to_your_project>/src/<your_package_namespace_path>/.
      • +
      • package is the package namespace for your project, following the same rules as for + packages in the Java programming language.
      -
    4. -
    -

    Here's an example:

    +

    Here's an example:

    -~/android_linux_sdk/tools $ ./activityCreator.py --out myproject your.package.name.ActivityName
    -package: your.package.name
    -out_dir: myproject
    -activity_name: ActivityName
    -~/android_linux_sdk/tools $ 
    +android create project \ +--target 1 \ +--path ./myProject \ +--activity MyActivity \ +--package com.example.myproject + -

    The activityCreator script generates the following files and directories (but will not overwrite existing ones):

    +

    The tool generates the following files and directories:

      -
    • AndroidManifest.xml The application manifest file, synced to the specified Activity class for the project.
    • -
    • build.xml An Ant file that you can use to build/package the application.
    • -
    • src/your/package/name/ActivityName.java The Activity class you specified on input.
    • -
    • your_activity.iml, your_activity.ipr, - your_activity.iws    [only - with the -ide intelliJ flag] intelliJ project - files.
    • -
    • res/   A directory to hold resources.
    • -
    • src/    The source directory. -
    • bin/    The output directory for the build script.
    • +
    • AndroidManifest.xml - The application manifest file, + synced to the specified Activity class for the project.
    • +
    • build.xml - Build file for Ant.
    • +
    • default.properties - Properties for the build system. Do not modify + this file.
    • +
    • build.properties - Customizable properties for the build system. You can edit this + file to overried default build settings used by Ant.
    • +
    • src/your/package/namespace/ActivityName.java - The Activity class + you specified during project creation.
    • +
    • bin/ - Output directory for the build script.
    • +
    • gen/ - Holds Ant-generated files, such as R.java.
    • +
    • libs/ - Holds private libraries.
    • +
    • res/ - Holds project resources.
    • +
    • src/ - Holds source code.
    • +
    • tests/ - Holds a duplicate of all-of-the-above, for testing purposes.
    -

    You can now move your folder wherever you want for development, but keep in mind - that you'll have to use the adb program in the tools/ folder to - send files to the emulator, so you'll need access between your solution and - the tools/ folder.

    - -

    Also, you should refrain from moving the - location of the SDK directory, since this will break the build scripts (they - will need to be manually updated to reflect the new SDK location before they will - work again).

    - -

    Building the Application with Ant

    -

    Use the Ant build.xml file generated by - activityCreator to build your application.

    -
      -
    1. If you don't have it, you can obtain Ant from the - Apache Ant home page. Install it and make - sure it is on your executable path.
    2. -
    3. Before calling Ant, you need to declare the JAVA_HOME environment variable to specify the path to where the JDK is installed. -

      Note: When installing JDK on Windows, the default is to install in the "Program Files" directory. This location will cause ant to fail, because of the space. To fix the problem, you can specify the JAVA_HOME variable like this: set JAVA_HOME=c:\Prora~1\Java\. The easiest solution, however, is to install JDK in a non-space directory, for example: c:\java\jdk1.6.0_02.

      -
    4. - - -
    5. If you have not done so already, follow the instructions for Creating a - New Project above to set up the project.
    6. -
    7. You can now run the Ant build file by simply typing ant in the same folder - as the build.xml file for your project. Each time you change - a source file or resource, you should run ant again and it will package up the - latest version of the application for you to deploy.
    8. -
    +

    Once you've created your project, you're ready to begin development. +You can move your project folder wherever you want for development, but keep in mind +that you must use the Android Debug Bridge +(adb) — located in the SDK tools/ directory — to send your application +to the emulator (discussed later). So you need access between your project solution and +the tools/ folder.

    + +

    Note: You should refrain from moving the +location of the SDK directory, because this will break the build scripts. (They +will need to be manually updated to reflect the new SDK location before they will +work again.)

    + -

    Setting Up Application Signing

    +

    Updating a project

    -

    As you begin developing Android applications, you should understand that all +

    If you're upgrading a project from an older version of the Android SDK or want to create +a new project from existing code, use the +android update project command to update the project to the new development +environment. You can also use this command to revise the build target of an existing project +(with the --target option). The android tool will generate any files and +folders (listed in the previous section) that are either missing or need to be updated, +as needed for the Android project.

    + +

    To update an existing Android project, open a command-line +and navigate to the tools/ directory of your SDK. Now run:

    +
    +android update project --target <targetID> --path path/to/your/project/
    +
    + +
      +
    • target is the "build target" for your application. It corresponds to + an Android platform library (including any add-ons, such as Google APIs) that you would + like to build your project against. To see a list of available targets and their corresponding IDs, + execute: android list targets.
    • +
    • path is the location of your project directory.
    • +
    + +

    Here's an example:

    +
    +android update project --target 2 --path ./myProject
    +
    + + +

    Preparing to Sign Your Application

    + +

    As you begin developing Android applications, understand that all Android applications must be digitally signed before the system will install -them on the emulator or an actual device.

    +them on an emulator or device. There are two ways to do this: +with a debug key (for immediate testing on an emulator or development device) +or with a private key (for application distribution).

    -

    The Android build tools help you get started quickly by signing your .apk -files with a debug key, prior to installing them on the emulator. This means +

    The Android build tools help you get started by automatically signing your .apk +files with a debug key at build time. This means that you can compile your application and install it on the emulator without having to generate your own private key. However, please note that if you intend -to publish your application, you must sign the application with your +to publish your application, you must sign the application with your own private key, rather than the debug key generated by the SDK tools.

    -

    To sign your applications, the ADT plugin requires the Keytool utility -included in the JDK. To set up your development environment for -signing, all you need to do is make sure that Keytool is available on your -machine that the build tools know how to find it.

    - -

    In most cases, you can tell the SDK build tools how to find Keytool by making -sure that -your JAVA_HOME environment variable is set and that it references a suitable -JDK. Alternatively, -you can add the JDK version of Keytool to your PATH variable.

    - -

    If you are developing on a version of Linux that originally came with Gnu -Compiler for Java, -make sure that the system is using the JDK version of Keytool, rather than the -gcj version. -If keytool is already in your PATH, it might be pointing to a symlink at -/usr/bin/keytool. -In this case, check the symlink target to make sure that it points to the -keytool in the JDK.

    - -

    In all cases, please read and understand Signing Your -Applications, which provides an overview of application signing on Android -and what it means to you as an Android application developer.

    - - -

    Running an Android Application

    -

    To run a compiled - application, you will upload the .apk file to the /data/app/ directory - in the emulator using the adb tool as described here:

    +

    Please read Signing Your +Applications, which provides a thorough guide to application signing on Android +and what it means to you as an Android application developer.

    + + + +

    Building Your Application

    + +

    There are two ways to build your application: one for testing/debugging your application +— debug mode — and one for building your final package for release — +release mode. As described in the previous +section, your application must be signed before it can be installed on an emulator +or device.

    + +

    Whether you're building in debug mode or release mode, you +need to use the Ant tool to compile and build your project. This will create the .apk file +that is installed onto the emulator or device. When you build in debug mode, the .apk +file is automatically signed by the SDK tools with a debug key, so it's instantly ready for installation +(but only onto an emulator or attached development device). +When you build in release mode, the .apk file is unsigned, so you must manually +sign it with your own private key, using Keytool and Jarsigner.

    + +

    It's important that you read and understand +Signing Your Applications, particularly +once you're ready to release your application and share it with end-users. That document describes +the procedure for generating a private key and then using it to sign your .apk file. +If you're just getting started, however, +you can quickly run your applications on an emulator or your own development device by building in +debug mode.

    + +

    If you don't have Ant, you can obtain it from the +Apache Ant home page. Install it and make +sure it is in your executable PATH. Before calling Ant, you need to declare the JAVA_HOME +environment variable to specify the path to where the JDK is installed.

    + +

    Note: When installing JDK on Windows, the default is to install +in the "Program Files" directory. This location will cause ant to fail, because of +the space. To fix the problem, you can specify the JAVA_HOME variable like this: +set JAVA_HOME=c:\Prora~1\Java\. The easiest solution, however, is to +install JDK in a non-space directory, for example: c:\java\jdk1.6.0_02.

    + + +

    Building in debug mode

    + +

    For immediate application testing and debugging, you can build your application +in debug mode and immediately install it on an emulator. In debug mode, the build tools automatically +sign your application with a debug key. However, you can (and should) also test your +application in release mode. Debug mode simply allows you to run your application without +manually signing the application.

    + +

    To build in debug mode:

    + +
      +
    1. Open a command-line and navigate to the root of your project directory.
    2. +
    3. Use Ant to compile your project in debug mode: +
      ant debug
      +

      This creates your Android application .apk file inside the project bin/ + directory, named <your_DefaultActivity_name>-debug.apk. The file + is already signed with the debug key.

      +
    4. +
    + +

    Each time you change a source file or resource, you must run Ant +again in order to package up the latest version of the application.

    + +

    To install and run your application on an emulator, see the following section +about Running Your Application.

    + + +

    Building in release mode

    + +

    When you're ready to release and distribute your application to end-users, you must build +your application in release mode. Once you have built in release mode, it's a good idea to perform +additional testing and debugging with the final .apk.

    + +

    To build in release mode:

    + +
      +
    1. Open a command-line and navigate to the root of your project directory.
    2. +
    3. Use Ant to compile your project in release mode: +
      ant release
      +

      This creates your Android application .apk file inside the project bin/ + directory, named <your_DefaultActivity_name>.apk.

      +

      Note: The .apk file is unsigned at this point. + You can't install it on an emulator or device until you sign it with your private key.

      +
    4. +
    + +

    Because release mode builds your application unsigned, your next step is to sign +it with your private key, in order to distribute it to end-users. To complete this procedure, +read Signing Your Applications.

    + +

    Once you have signed your application with a private key, you can install it on an +emulator or device as discussed in the following section about +Running Your Application. +You can also try installing it onto a device from a web server. +Simply upload the signed APK to a web site, then load the .apk URL in your Android web browser to +download the application and begin installation. +(On your device, be sure you have enabled Settings > Applications > Unknown sources.)

    + + +

    Running Your Application

    + +

    Unless you'll be running your application on device hardware, +you need to launch an emulator upon which you will install your application. +An instance of the Android emulator runs a specific Android platform with specific device configuration +settings. The platform and configuration is defined with an Android Virtual Device (AVD). +So before you can launch your emulator, you must define an AVD.

    + +

    If you'll be running your application on device hardware, please read about +Developing On a Device instead.

    +
      -
    1. Start the emulator (run <your_sdk_dir>/tools/emulator from the command line)
    2. -
    3. On the emulator, navigate to the home screen (it is best not to have that - application running when you reinstall it on the emulator; press the Home key - to navigate away from that application).
    4. -
    5. Run adb install myproject/bin/<appname>.apk to upload - the executable. So, for example, to install the Lunar Lander sample, navigate - in the command line to <your_sdk_dir>/sample/LunarLander and type ../../tools/adb install bin/LunarLander.apk
    6. -
    7. In the emulator, open the list of available applications, and scroll down to - select and start your application.
    8. +
    9. Create an AVD +
        +
      1. Open a command-line and navigate to your SDK package's + tools/ directory.
      2. +
      3. First, you need to select a "deployment target." To view available targets, execute: +
        android list targets
        +

        This will output a list of available Android targets, such as:

        +
        +id:1
        +    Name: Android 1.1
        +    Type: platform
        +    API level: 2
        +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
        +id:2
        +    Name: Android 1.5
        +    Type: platform
        +    API level: 3
        +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
        +
        +

        Find the target that matches the Android platform upon which you'd like + to run your application. Note the integer value of the id — + you'll use this in the next step.

        +
      4. +
      5. Create a new AVD using your selected deployment target: +
        android create avd --name <your_avd_name> --target <targetID>
        +
      6. Next, you'll be asked whether you'd like to create a custom hardware profile. + If you respond "yes," you'll be presented with a series of prompts to define various aspects of the + device hardware (leave entries blank to use default values, which are shown in brackets). Otherwise, + press return to use all default values ("no" is the default).
      7. + +
      +
    10. + +
    11. Launch an emulator
    12. +

      From your SDK's tools/ directory, launch an emulator + using an existing AVD (created above): +

      emulator -avd <your_avd_name>
      +

      An instance of the emulator will now launch, running the target and configuration + defined by your AVD.

      + + +
    13. Install your application +

      From your SDK's tools/ directory, install the .apk on the emulator: +

      adb install /path/to/your/application.apk
      +

      If there is more than one emulator running, you must specify the emulator upon which to install + the application, by its serial number, with the -s option. For example:

      +
      adb -s emulator-5554 install /my/project/path/myapp.apk
      +
    14. +
    15. Open your application +

      In the emulator, open the list of available applications to find + and open your application.

      +
    -

    Note: When you install an Activity for the - first time, you might have to restart the emulator before it shows up in the - application launcher, or other applications can call it. This is because - the package manager usually only examines manifests completely on emulator - startup.

    -

    Attaching a Debugger to Your Application

    +

    If you don't see your application on the emulator. Try restarting the emulator +(with the same AVD). Sometimes when you install an Activity for the +first time, it won't show up in the application launcher or be accessible by other +applications. This is because the package manager usually examines manifests +completely only on emulator startup.

    + +

    Tip: If you have only one emulator running, +you can build your application and install it on the emulator in one simple step. +Navigate to the root of your project directory and use Ant to compile the project +with install mode: +ant install. This will build your application, sign it with the debug key, +and install it on the currently running emulator. +If there is more than one emulator currently running +when using the install command, it will fail — it can't select between the +multiple emulators.

    + +

    For more information on the tools used above, please see the following documents:

    + + + +

    Attaching a Debugger to Your Application

    +

    This section describes how to display debug information on the screen (such as CPU usage), as well as how to hook up your IDE to debug running applications on the emulator.

    Attaching a debugger is automated using the Eclipse plugin, but you can configure other IDEs to listen on a debugging port to receive debugging - information.

    + information:

      -
    1. Start the Dalvik Debug Monitor Server (DDMS) - tool , which +
    2. Start the Dalvik Debug Monitor + Server (DDMS) tool, which acts as a port forwarding service between your IDE and the emulator.
    3. Set optional debugging configurations on - your emulator, such as blocking application startup for an activity + your emulator, such as blocking application startup for an Activity until a debugger is attached. Note that many of these debugging options can be used without DDMS, such as displaying CPU usage or screen refresh rate on the emulator.
    4. -
    5. Configure your IDE to attach to port 8700 for debugging. We - include information on - how to set up Eclipse to debug your project.
    6. - +
    7. Configure your IDE to attach to port 8700 for debugging. Read + about + Configuring Your IDE to Attach to the Debugging Port.
    diff --git a/docs/html/guide/developing/tools/aidl.jd b/docs/html/guide/developing/tools/aidl.jd index 96e4fec7cc1a2364763db3d34d691245d929f06a..f370a804a401722231ac1f7f69db73ec5a3e4942 100644 --- a/docs/html/guide/developing/tools/aidl.jd +++ b/docs/html/guide/developing/tools/aidl.jd @@ -1,6 +1,25 @@ page.title=Designing a Remote Interface Using AIDL @jd:body + + + +

    Since each application runs in its own process, and you can write a service that runs in a different process from your Application's UI, sometimes you need to pass objects between processes. On the Android platform, one process can not normally access the memory @@ -10,7 +29,7 @@ the operating system can understand, and "marshall" the object across that bound

    The code to do that marshalling is tedious to write, so we provide the AIDL tool to do it for you.

    -

    AIDL (Android Interface Definition Language) is an AIDL (Android Interface Definition Language) is an IDL language used to generate code that enables two processes on an Android-powered device to talk using interprocess communication (IPC). If you have code @@ -20,12 +39,9 @@ generate code to marshall the parameters.

    The AIDL IPC mechanism is interface-based, similar to COM or Corba, but lighter weight. It uses a proxy class to pass values between the client and the implementation.

    -

    This page includes the following main topics:

    - -

    Implementing IPC Using AIDL

    + + +

    Implementing IPC Using AIDL

    Follow these steps to implement an IPC service using AIDL.

    1. Create your .aidl file - This @@ -46,7 +62,8 @@ generate code to marshall the parameters.

      Service.onBind(Intent)} to return an instance of your class that implements your interface.
    -

    Create an .aidl File

    + +

    Create an .aidl File

    AIDL is a simple syntax that lets you declare an interface with one or more methods, that can take parameters and return values. These parameters and return values can be of any type, even other AIDL-generated interfaces. However, it @@ -117,7 +134,7 @@ interface IBankAccountService { int getCustomerList(in String branch, out String[] customerList); } -

    Implementing the Interface

    +

    Implementing the Interface

    AIDL generates an interface file for you with the same name as your .aidl file. If you are using the Eclipse plugin, AIDL will automatically be run as part of the build process (you don't need to run AIDL first and then build your project). @@ -152,7 +169,7 @@ private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){

  • Only methods are supported; you cannot declare static fields in an AIDL interface.
  • -

    Exposing Your Interface to Clients

    +

    Exposing Your Interface to Clients

    Now that you've got your interface implementation, you need to expose it to clients. This is known as "publishing your service." To publish a service, inherit {@link android.app.Service Service} and implement {@link android.app.Service#onBind @@ -165,8 +182,8 @@ private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){ exposing_a_service} } - -

    Pass by value Parameters using Parcelables

    + +

    Pass by value Parameters using Parcelables

    If you have a class that you would like to send from one process to another through an AIDL interface, you can do that. You must ensure that the code for your class is available @@ -181,25 +198,12 @@ current state of the object and writes it to a parcel. value in a parcel into your object.

  • Add a static field called CREATOR to your class which is an object implementing the {@link android.os.Parcelable.Creator Parcelable.Creator} interface.
  • -
  • Last but not least: -
      -
    • If you are developing with Eclipse/ADT, follow these steps: -
        -
      1. In the Package Explorer view, right-click on the project.
      2. -
      3. Choose Android Tools > Create Aidl preprocess file -for Parcelable classes.
      4. -
      5. This will create a file called "project.aidl" in the root of the project. -The file will be automatically used when compiling an aidl file that uses the -parcelable classes.
      6. -
      -
    • -
    • If you are developing with Ant or are using a custom build process, create an aidl file +
    • Last but not least, create an aidl file that declares your parcelable class (as shown below). If you are using a custom build process, do not add the aidl file to your build. Similar to a header file in C, the aidl file isn't compiled.
    • -
    -
  • - + +

    AIDL will use these methods and fields in the code it generates to marshall and unmarshall your objects.

    Here is an example of how the {@link android.graphics.Rect} class implements the @@ -269,7 +273,7 @@ values for whatever the caller is trying to do. See Security and Permissions for more on how to keep your application secure from malware.

    -

    Calling an IPC Method

    +

    Calling an IPC Method

    Here are the steps a calling class should make to call your remote interface:

    1. Declare a variable of the interface type that your .aidl file defined.
    2. diff --git a/docs/html/guide/developing/tools/avd.jd b/docs/html/guide/developing/tools/avd.jd new file mode 100644 index 0000000000000000000000000000000000000000..b8f205ec0f7e60409f7a8e7752914b0b2d3cee71 --- /dev/null +++ b/docs/html/guide/developing/tools/avd.jd @@ -0,0 +1,504 @@ +page.title=Android Virtual Devices +@jd:body + +
      +
      + +

      AVD quickview

      +
        +
      • You need to create an AVD to run any app in the Android emulator
      • +
      • Each AVD is a completely independent virtual device, with its own + hardware options, system image, and data storage. +
      • You create AVD configurations to model different device environments + in the Android emulator.
      • +
      +

      In this document

      +
        +
      1. Creating an AVD +
          +
        1. Listing targets
        2. +
        3. Selecting a target
        4. +
        5. Creating the AVD
        6. +
        7. Setting hardware emulation options
        8. +
        9. Default location of the AVD files
        10. +
        +
      2. +
      3. Managing AVDs +
          +
        1. Moving an AVD
        2. +
        3. Updating an AVD
        4. +
        5. Deleting an AVD
        6. +
        +
      4. +
      5. Command-line options
      6. +
      +

      See Also

      +
        +
      1. Android + Emulator
      2. +
      +
      +
      + +

      Android Virtual Devices (AVDs) are configurations of emulator options that let +you better model an actual device.

      + +

      Each AVD is made up of:

      + +
        +
      • A hardware profile.  You can set options to define the hardware +features of the virtual device. For example, you can define whether the device +has a camera, whether it uses a physical QWERTY keyboard or a dialing pad, how +much memory it has, and so on.
      • +
      • A mapping to a system image.  You can define what version of the +Android platform will run on the virtual device. You can choose a version of the +standard Android platform or the system image packaged with an SDK add-on.
      • +
      • Other options.  You can specify the emulator skin you want to use +with the AVD, which lets you control the screen dimensions, appearance, and so +on. You can also specify the emulated SD card to use with the AVD.
      • +
      • A dedicated storage area on your development machine, in which is stored the +device's user data (installed applications, settings, and so on) and emulated SD +card.
      • +
      + +

      You can create as many AVDs as you need, based on the types of devices you +want to model and the Android platforms and external libraries you want to run +your application on.

      + +

      In addition to the options in an AVD configuration, you can also +specify emulator command-line options at launch or by using the emulator +console to change behaviors or characteristics at run time. For a complete +reference of emulator options, please see the Emulator +documentation.

      + +

      To create and manage AVDs, you use the android tool provided in the Android +SDK. For more information about how to work with AVDs from inside +your development environment, see Developing in Eclipse with +ADT or Developing in +Other IDEs, as appropriate for your environment.

      + +

      Creating an AVD

      + + + +

      To create an AVD, you use the android tool, a command-line utility +available in the <sdk>/tools/ directory. Managing AVDs is one +of the two main function of the android tool (the other is creating and updating +Android projects). Open a terminal window and change to the +<sdk>/tools/ directory, if needed

      + +

      To create each AVD, you issue the command android create avd, +with options that specify a name for the new AVD and the system image you want +to run on the emulator when the AVD is invoked. You can specify other options on +the command line also, such as to create an emulated SD card for the new AVD, set +the emulator skin to use, or set a custom location for the AVD's files.

      + +

      Here's the command-line usage for creating an AVD:

      + +
      android create avd -n <name> -t <targetID> [-<option> <value>] ... 
      + +

      You can use any name you want for the AVD, but since you are likely to be +creating multiple AVDs, you should choose a name that lets you recognize the +general characteristics offered by the AVD.

      + +

      As shown in the usage above, you must use the -t (or +--target) argument when creating a new AVD. The argument sets up a +mapping between the AVD and the system image that you want to use whenever the +AVD is invoked. You can specify any Android system image that is available in +your local SDK — it can be the system image of a standard Android platform +version or that of any SDK add-on. Later, when applications use the AVD, they'll +be running on the system that you specify in the -t argument.

      + +

      To specify the system image to use, you refer to its target ID +— an integer — as assigned by the android tool. The target ID is not +derived from the system image name, version, or API Level, or other attribute, +so you need to have the android tool list the available system images and the +target ID of each, as described in the next section. You should do this +before you run the android create avd command. +

      + +

      Listing targets

      + +

      To generate a list of system image targets, use this command:

      + +
      android list targets
      + +

      The android tool scans the <sdk>/platforms and +<sdk>/add-ons directories looking for valid system images and +then generates the list of targets. Here's an example of the command output: +

      + +
      Available Android targets:
      +id:1
      +    Name: Android 1.1
      +    Type: platform
      +    API level: 2
      +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
      +id:2
      +    Name: Android 1.5
      +    Type: platform
      +    API level: 3
      +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
      +id:3
      +    Name: Google APIs
      +    Type: add-on
      +    Vendor: Google Inc.
      +    Description: Android + Google APIs
      +    Based on Android 1.5 (API level 3)
      +    Libraries:
      +    * com.google.android.maps (maps.jar)
      +        API for Google Maps
      +    Skins: HVGA (default), HVGA-L, QVGA-P, HVGA-P, QVGA-L
      + +

      Selecting a target

      + +

      Once you have generated the list of targets available, you can look at the +characteristics of each system image — name, API Level, external +libraries, and so on — and determine which target is appropriate for the +new AVD.

      + +

      Keep these points in mind when you are selecting a system image target for +your AVD:

      +
        +
      • The API Level of the target is important, because your application will not +be able to run on a system image whose API Level is less than that required by +your application, as specified in the minSdkVersion attribute of +the application's manifest file. For more information about the relationship +between system API Level and application minSdkVersion, see Specifying +Minimum System API Version. +
      • Creating at least one AVD that uses a target whose API Level is greater than +that required by your application is strongly encouraged, because it allows you to +test the forward-compatibility of your application. Forward-compatibility +testing ensures that, when users who have downloaded your application receive a +system update, your application will continue to function normally.
      • +
      • If your application declares a uses-library element in its +manifest file, the application can only run on a system image in which that +external library is present. If you want your application to run on the AVD you +are creating, check the application's uses-library element and +select a system image target that includes that library. + +
      + +

      Creating the AVD

      + +

      When you've selected the target you want to use and made a note of its ID, +use the android create avd command to create the AVD, supplying the +target ID as the -t argument. Here's an example that creates an +AVD with name "my_android1.5" and target ID "2" (the standard Android 1.5 +system image in the list above):

      + +
      android create avd -n my_android1.5 -t 2
      + +

      If the target you selected was a standard Android system image ("Type: +platform"), the android tool next asks you whether you want to create a custom +hardware profile.

      + +
      Android 1.5 is a basic Android platform.
      +Do you wish to create a custom hardware profile [no]
      + +

      If you want to set custom hardware emulation options for the AVD, enter +"yes" and set values as needed. If you want to use the default hardware +emulation options for the AVD, just press the return key (the default is "no"). +The android tool creates the AVD with name and system image mapping you +requested, with the options you specified. + +

      If you are creating an AVD whose target is an SDK add-on, +the android tool does not allow you to set hardware emulation options. It +assumes that the provider of the add-on has set emulation options appropriately +for the device that the add-on is modeling, and so prevents you from resetting +the options.

      + +

      For a list of options you can use in the android create avd +command, see the table in Command-line options for AVDs, +at the bottom of +this page.

      + +

      Setting hardware emulation options

      + +

      When are creating a new AVD that uses a standard Android system image ("Type: +platform"), the android tool lets you set hardware emulation options for virtual +device. The table below lists the options available and the default values, as +well as the names of properties that store the emulated hardware options in the AVD's +configuration file (the config.ini file in the AVD's local directory).

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      CharacteristicDescriptionProperty
      Device ram sizeThe amount of physical RAM on the device, in megabytes. Default value is "96". +hw.ramSize
      Touch-screen supportWhether there is a touch screen or not on the device. Default value is "yes".hw.touchScreen + + +
      Trackball support Whether there is a trackball on the device. Default value is "yes".hw.trackBall
      Keyboard supportWhether the device has a QWERTY keyboard. Default value is "yes".hw.keyboard
      DPad supportWhether the device has DPad keys. Default value is "yes".hw.dPad
      GSM modem supportWhether there is a GSM modem in the device. Default value is "yes".hw.gsmModem
      Camera supportWhether the device has a camera. Default value is "no".hw.camera
      Maximum horizontal camera pixelsDefault value is "640".hw.camera.maxHorizontalPixels
      Maximum vertical camera pixelsDefault value is "480".hw.camera.maxVerticalPixels
      GPS supportWhether there is a GPS in the device. Default value is "yes".hw.gps
      Battery supportWhether the device can run on a battery. Default value is "yes".hw.battery
      AccelerometerWhether there is an accelerometer in the device. Default value is "yes".hw.accelerometer
      Audio recording supportWhether the device can record audio. Default value is "yes".hw.audioInput
      Audio playback supportWhether the device can play audio. Default value is "yes".hw.audioOutput
      SD Card supportWhether the device supports insertion/removal of virtual SD Cards. Default value is "yes".hw.sdCard
      Cache partition supportWhether we use a /cache partition on the device. Default value is "yes".disk.cachePartition
      Cache partition sizeDefault value is "66MB".disk.cachePartition.size
      + +

      Default location of the AVD files

      + +

      When you create an AVD, the android tool creates a dedicated directory for it +on your development computer. The directory contains the AVD configuration file, +the user data image and SD card image (if available), and any other files +associated with the device. Note that the directory does not contain a system +image — instead, the AVD configuration file contains a mapping to the +system image, which it loads when the AVD is launched.

      + +

      The android tool also creates a <AVD name>.ini file for the AVD at the +root of the .android/avd directory on your computer. The file specifies the +location of the AVD directory and always remains at the root the .android +directory.

      + +

      By default, the android tool creates the AVD directory inside +~/.android/avd/ (on Linux/Mac), C:\Documents and +Settings\<user>\.android\ on Windows XP, and +C:\Users\<user>\.android\ on Windows Vista. +If you want to use a custom location for the AVD directory, you +can do so by using the -p <path> option when +you create the AVD:

      + +
      android create avd -n my_android1.5 -t 2 -p path/to/my/avd
      + +

      If the .android directory is hosted on a network drive, we recommend using +the -p option to place the AVD directory in another location. +The AVD's .ini file remains in the .android directory on the network +drive, regardless of the location of the AVD directory.

      + +

      Managing AVDs

      + +

      The sections below provide more information about how to manage AVDs once you've created them.

      + +

      Moving an AVD

      + +

      If you want to move or rename an AVD, you can do so using this command:

      + +
      android move avd -n <name> [-<option> <value>] ...
      + +

      The options for this command are listed in Command-line +options for AVDs at the bottom of this page.

      + +

      Updating an AVD

      + +

      If, for any reason, the platform/add-on root folder has its name changed (maybe because the user has installed an update of the platform/add-on) then the AVD will not be able to load the system image that it is mapped to. In this case, the android list targets command will produce this output: + +

      The following Android Virtual Devices could not be loaded: 
      +Name: foo 
      +Path: <path>/.android/avd/foo.avd 
      +Error: Invalid value in image.sysdir. Run 'android update avd -n foo' 
      + +

      To fix this error, use the android update avd command to recompute the path to the system images.

      + +

      Deleting an AVD

      + +

      You can use the android tool to delete an AVD. Here is the command usage:

      + +
      android delete avd -n <name> 
      + +

      When you issue the command, the android tool looks for an AVD matching the +specified name deletes the AVD's directory and files.

      + + +

      Command-line options for AVDs

      + +

      The table below lists the command-line options you can use with the +android tool.

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ActionOptionDescriptionComments
      list avds List all known AVDs, with name, path, target, and skin.  
      create avd-n <name> or
      The name for the AVD.Required
      -t <targetID>Target ID of the system image to use with the new AVD.Required. To obtain a list of available targets, use android list + targets.
      -c <path> or
      + -c <size>[K|M]
      The path to the SD card image to use with this AVD or the size of a new SD + card image to create for this AVD.Examples: -c path/to/sdcard or -c 1000M
      -fForce creation of the AVDBy default, if the name of the AVD being created matches that of an + existing AVD, the android tool will not create the new AVD or overwrite + the existing AVD. If you specify the -f option, however, the + android tool will automatically overwrite any existing AVD that has the + same name as the new AVD. The files and data of the existing AVD are + deleted.
      -p <path>Path to the location at which to create the directory for this AVD's +files. 
      -s <name> or
      + -s <width>-<height>
      The skin to use for this AVD, identified by name or dimensions.The android tool scans for a matching skin by name or dimension in the +skins/ directory of the target referenced in the -t +<targetID> argument. Example: -s HVGA-L
      delete avd-n <name>Delete the specified AVD.Required
      move avd-n <name>The name of the AVD to move.Required
      -p <path>The path to the new location for the AVD. 
      -r <new-name>Rename the AVD. 
      update avds Recompute the paths to all system images. 
      + diff --git a/docs/html/guide/developing/tools/emulator.jd b/docs/html/guide/developing/tools/emulator.jd index 769491b4f14bdffd97a5c4754105cb9529a6d8f5..82d3c8dd6d0af4aed88d825da7881f2014861692 100644 --- a/docs/html/guide/developing/tools/emulator.jd +++ b/docs/html/guide/developing/tools/emulator.jd @@ -14,30 +14,31 @@ using your mouse or keyboard to generate events for your application. It also provides a screen in which your application is displayed, together with any other Android applications running.

      -

      To help you model and test your application, the emulator lets your application -use the services of the Android platform to invoke other applications, access the -network, play audio and video, store and retrieve data, notify the user, and render -graphical transitions and themes.

      +

      To let you model and test your application more easily, the emulator supports +Android Virtual Device (AVD) configurations. AVDs let you specify the Android +platform that you want to run on the emulator, as well as the hardware options +and emulator skin files tht you want to use. Once your application is running on +the emulator, it can use the services of the Android platform to invoke other +applications, access the network, play audio and video, store and retrieve data, +notify the user, and render graphical transitions and themes.

      The emulator also includes a variety of debug capabilities, such as a console from which you can log kernel output, simulate application interrupts (such as arriving SMS messages or phone calls), and simulate latency effects and dropouts on the data channel.

      - - -

      In this document:

      1. Overview
      2. Starting and Stopping the Emulator
      3. +
      4. Android Virtual Devices and the Emulator
      5. Controlling the Emulator
      6. Emulator Startup Options
      7. Working with Emulator Disk Images
          -
        1. System Images
        2. +
        3. Default Images
        4. Runtime Images: User Data and SD Card
        5. Temporary Images
      8. @@ -76,7 +77,8 @@ on the data channel.

      9. Installing Applications on the Emulator
      10. SD Card Emulation
          -
        1. Creating a Disk Image
        2. +
        3. Creating an SD card image using the android tool
        4. +
        5. Creating an SD card image using mksdcard
        6. Copying Files to a Disk Image
        7. Loading the Disk Image at Emulator Startup
      11. @@ -92,12 +94,14 @@ on the data channel.

        Overview

        The Android emulator is a QEMU-based application that provides a virtual ARM -mobile device on which you can run your Android applications. It provides a full -Android system stack, down to the kernel level, and includes a set of +mobile device on which you can run your Android applications. It runs a full +Android system stack, down to the kernel level, that includes a set of preinstalled applications (such as the dialer) that you can access from your -applications. It provides a skinnable mobile device UI, customizable key -mappings, and a variety of commands and options for controlling the behaviors of -the emulated environment.

        +applications. You can choose what version of the Android system you want to +run in the emulator by configuring AVDs, and you can also customize the +mobile device skin and key mappings. When launching the emulator and at runtime, +you can use a variety of commands and options to control the its behaviors. +

        The Android system image distributed in the SDK contains ARM machine code for the Android Linux kernel, the native libraries, the Dalvik VM, and the various @@ -132,9 +136,9 @@ it for developing Android applications.

        During development and testing of your application, you install and run your application in the Android emulator. You can launch the emulator as a standalone application, from a command line, or you can use it as part of your Eclipse -development environment. In either case, you can specify the startup options -described in this document to control the emulator. -

        +development environment. In either case, you specify the AVD configuration to +load and any startup options you want to use, as described in this document. +

        You can run your application on a single instance of the emulator or, depending on your needs, you can start multiple emulator instances and run your @@ -146,9 +150,14 @@ Emulation, SMS Emulation, and Emulator Networking

        To start an instance of the emulator from the command line, change to the -tools/ folder of the SDK and enter emulator or -./emulator. This initializes the Android system and you will see -the emulator window appear on your screen.

        +tools/ folder of the SDK. Enter emulator command +like this:

        + +
        emulator -avd <avd_name>
        + +

        This initializes the emulator and loads an AVD configuration (see the next +section for more information about AVDs). You will see the emulator window +appear on your screen.

        If you are working in Eclipse, the ADT plugin for Eclipse installs your application and starts the emulator automatically, when you run or debug @@ -163,6 +172,27 @@ on the Emulator for information about how to install your application.

        + + +

        Android Virtual Devices and the Emulator

        + +

        To use the emulator, you first must create one or more AVD configurations. In each +configuration, you specify an Android platform to run in the emulator and the set of hardware +options and emulator skin you want to use. Then, when you launch the emulator, you specify +the AVD configuration that you want to load.

        + +

        To specify the AVD you want to load when starting the emulator, you use the +-avd argument, as shown in the previous section.

        + +

        Each AVD functions as an independent device, with its own private storage for +user data, SD card, and so on. When you launch the emulator with an AVD configuration, +it automatically loads the user data and SD card data from the AVD directory. By default, +the emulator stores the user data, SD card data, and cache in the AVD directory.

        + +

        To create and manage AVDs you use the android tool, a command-line utility +included in the SDK. For complete information about how to set up AVDs, see Android Virtual Devices.

        +

        Controlling the Emulator

        You can use emulator startup options and when launching the emulator, to control its appearance or behavior. Here's the command-line usage for launching the emulator with options:

        -
        emulator [-<option> [<value>]] ... [-<qemu args>]
        +
        emulator -avd <avd_name> [-<option> [<value>]] ... [-<qemu args>]

        The table below summarizes the available options.

        @@ -292,7 +322,7 @@ Here's the command-line usage for launching the emulator with options:

        - Help + Help -help Print a list of all emulator options.   @@ -331,9 +361,22 @@ Here's the command-line usage for launching the emulator with options:

        Print help for defining a custom key mappings file.   - - Disk Images + -help-virtual-device + Print help for Android Virtual Device usage. +   + + + AVD + -avd <avd_name> or
        + @<avd_name> + Required. Specifies the AVD to load for this emulator + instance. + You must create an AVD configuration before launching the emulator. For + information, see
        Android + Virtual Devices. + + Disk Images -cache <filepath> Use <filepath> as the working cache partition image. Optionally, you can specify a path relative to the current working directory. @@ -345,13 +388,7 @@ Here's the command-line usage for launching the emulator with options:

        Use <filepath> as the working user-data disk image. Optionally, you can specify a path relative to the current working directory. If -data is not used, the emulator looks for a file named "userdata-qemu.img" - in the directory specified in <datadir>. ~/.android/SDK-1.0 (on Linux/Mac) or - C:\Documents and Settings\<user>\Local Settings\Application Data\Android\SDK-1.0 (on Windows). -

        If you use -data <filepath> but the file does not exist, the emulator creates - a file at that location using the specified name.

        -

        See Running Multiple Emulator Instances for information about how - to use -data to let multiple emulator instances preserve their user data across sessions.

        -

        For more information on disk images, use -help-disk-images.

        + in the storage area of the AVD being used (see -avd). + -initdata <filepath> When resetting the user-data image (through -wipe-data), copy the contents of this file to the new user-data disk image. By default, the emulator copies the <system>/userdata.img. Optionally, you can specify a path relative to the current working directory. See also -wipe-data.

        For more information on disk images, use -help-disk-images.

        + -nocache Start the emulator without a cache partition. @@ -400,12 +441,14 @@ Here's the command-line usage for launching the emulator with options:

        Optionally, you can specify a path relative to the current working directory. For more information on disk images, use -help-disk-images.

        + -wipe-data Reset the current user-data disk image (that is, the file specified by -datadir and @@ -448,8 +491,8 @@ Here's the command-line usage for launching the emulator with options:

        -shell-serial <device> Enable the root shell (as in -shell and specify the QEMU character device to use for communication with the shell. - <device> must be a QEMU device type. See the documentation for 'serial -dev' at - http://www.bellard.org/qemu/qemu-doc.html#SEC10 + <device> must be a QEMU device type. See the documentation for '-serial dev' at + http://www.bellard.org/qemu/qemu-doc.html#SEC10 for a list of device types.

        Here are some examples:

        @@ -679,7 +722,8 @@ scale in direct relationship with <delay> values.

        -skin <skinID> Start the emulator with the specified skin. - The SDK includes a choice of four skins:
        + The standard Android platforms includes a choice of + four skins:
      12. HVGA-L (480x320, landscape)
      13. HVGA-P (320x480, portrait) (default)
      14. QVGA-L (320x240, landscape)
      15. @@ -702,10 +746,16 @@ disk image containing an emulator-specific kernel, the Android system, a ramdisk image, and writeable images for user data and simulated SD card.

        To run properly, the emulator requires access to a specific set of disk image -files. The Android SDK includes default versions of the required images, stored -in predetermined locations in the SDK directory structure. At startup, the -emulator looks for and reads the image files, using their default names and -storage locations.

        +files. By default, the Emulator always looks for the disk images in the +private storage area of the AVD in use. If no images exist there when +the Emulator is launched, it creates the images in the AVD directory based on +default versions stored in the SDK.

        + +

        Note: The default storage location for +AVDs is in ~/.android/avd on OS X and Linux, C:\Documents and +Settings\<user>\.android\ on Windows XP, and +C:\Users\<user>\.android\ +on Windows Vista.

        To let you use alternate or custom versions of the image files, the emulator provides startup options that override the default locations and filenames of @@ -713,32 +763,26 @@ the image files. When you use the options, the emulator searches for the image file under the image name or location that you specify; if it can not locate the image, it reverts to using the default names and location.

        -

        The emulator uses three types of image files: system image files, runtime +

        The emulator uses three types of image files: default image files, runtime image files, and temporary image files. The sections below describe how to override the location/name of each type of file.

        - -

        System Images

        + +

        Default Images

        -

        System images contain system data and default settings without which the -emulator can not run. The image files are read-only — the emulator reads -the images at startup and does not modify them during the session.

        - -

        All of the system image files are stored in a single directory. By default, -the system images are stored in the lib/images' under the -emulator's program location.

        +

        When the emulator launches but does not find an existing user data image in +the active AVD's storage area, it creates a new one from a default version +included in the SDK. The default user data image is read-only. The image +files are read-only.

        The emulator provides the -system <dir> startup option to -let you override the location under which the emulator looks for the system -images files.

        +let you override the location under which the emulator looks for the default +user data image.

        -

        The emulator also provides startup options that let you override the names of -the system images, as described in the table below. When you use one of the -options, the emulator looks in the default directory, or in a custom location -(if you specified -system <dir>). Note that, if you provide -alternate system image file, it must contain the same type of data as the -default. For example, your override of the system.img file must point to a disk -image containing an Android system.

        +

        The emulator also provides a startup option that lets you override the name +of the default user data image, as described in the table below. When you use the +option, the emulator looks in the default directory, or in a custom location +(if you specified -system <dir>).

        @@ -748,6 +792,7 @@ image containing an Android system.

        + @@ -784,13 +829,7 @@ partition and removable storage media on actual device.

        The emulator provides a default user-data disk image. At startup, the emulator creates the default image as a copy of the system user-data image (user-data.img), -described above. The emulator stores the default image in this location on -on your development machine:

        - -
          -
        • Linux and OS X: ~/.android/SDK-1.0
        • -
        • Windows: C:\Documents and Settings\<user>\Local Settings\Application Data\Android\SDK-1.0
        • -
        +described above. The emulator stores the new image with the files of the active AVD.

      16. Security and Permissions
      17. @@ -61,6 +62,7 @@
      18. <provider>
      19. <receiver>
      20. <service>
      21. +
      22. <uses-configuration>
      23. <uses-library>
      24. <uses-permission>
      25. <uses-sdk>
      26. @@ -84,7 +86,7 @@
      27. Accelerometer
      28. --> -
      29. Location
      30. +
      31. Location and Maps
      32. +
      33. App Widgets
      34. @@ -100,7 +103,6 @@
          -
        • In Eclipse, with ADT
        • In Other IDEs
        • On a Device
        • @@ -110,9 +112,10 @@
          • aapt
          • adb
          • -
          • activitycreator
          • +
          • android
          • aidl
          • +
          • AVDs
          • ddms
          • dx
          • Draw 9-Patch
          • @@ -140,6 +143,12 @@
          • Best Practices

              +
            • + + +
            • Designing for Performance
            • Designing for Responsiveness
            • Designing for Seamlessness
            • diff --git a/docs/html/guide/practices/ui_guidelines/index.jd b/docs/html/guide/practices/ui_guidelines/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..e19d5b49f3ff8b4c7fbeb71ccfd708fa5e2d6aff --- /dev/null +++ b/docs/html/guide/practices/ui_guidelines/index.jd @@ -0,0 +1,28 @@ +page.title=User Interface Guidelines +@jd:body + + + + + +

              The Android UI team has begun developing guidelines for the interaction and +design of Android applications. Look here for articles that describe these +visual guidelines as we release them.

              + + +
              +
              Widget Design Guidelines
              +
              Widgets are a new feature introduced in Cupcake. A widget displays +an application's most important or timely information at a glance, on a user's +Home screen. These design guidelines describe how to design widgets that fit +with others on the Home screen. They include links to graphics files and +templates that will make your designer's life easier.
              + +
              + + + + + + + diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd new file mode 100644 index 0000000000000000000000000000000000000000..514b315c0a98bbdc7ae57f9d6297b06df08132e9 --- /dev/null +++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd @@ -0,0 +1,274 @@ +page.title=Widget Design Guidelines +@jd:body + +
              +
              + +

              Widget design quickview

              + +
                +
              • Widgets have six standard sizes on the Home screen
              • +
              • Widgets have standards for size, frames, shadows, and file format, which you can copy
              • +
              • A few tricks make it easier to design widgets that fit graphically on the Home screeen
              • +
              + +

              In this document

              + +
                +
              1. Standard widget anatomy
              2. +
              3. Designing a widget
              4. +
              5. Standard widget sizes
              6. +
              7. Standard widget frames
              8. +
              9. Standard widget shadows
              10. +
              11. Widget graphics tips and tricks
              12. +
              13. Widget graphics file format
              14. +
              + +

              See also

              + +
                +
              1. AppWidgets topic in the Dev Guide
              2. +
              3. AppWidgets blog post
              4. +
              + +
              +
              + + +

              Widgets are a feature introduced in Android 1.5. A widget displays an +application's most important or timely information at a glance, on a user's Home +screen. The standard Android system image includes several examples of widgets, +including widgets for Analog Clock, Music, and other applications.

              + +

              Users pick the widgets they want to display on their Home screens by touching +& holding an empty area of the Home screen, selecting Widgets from the menu, +and then selecting the widget they want.

              + +

              Example
+Widgets

              + +

              This document describes how to design a widget so it fits graphically with +other widgets and with the other elements of the Android Home screen. It also +describes some standards for widget artwork and some widget graphics tips and +tricks from the Android team.

              + +

              For information about developing widgets, see the AppWidgets section of +the Developer's Guide and the AppWidgets blog post.

              + + +

              Standard widget anatomy

              + +

              Typical Android widgets have three main components: A bounding box, a frame, +and the widget's graphical controls and other elements. Well-designed widgets +leave some padding between the edges of the bounding box and the frame, and +between the inner edges of the frame and the widget's controls. Widgets designed +to fit visually with other widgets on the Home screen take cues from the other +elements on the Home screen for alignment; they also use standard shading +effects. All of these details are described in this document. + +

              Standard Widget Sizes in Portrait Orientation
              +

              + +

               

              + +

              Standard Widget Sizes in Landscape Orientation
              +

              + + +

              Designing a widget

              + +
                +
              1. Select a bounding box size for your widget.
              2. + +

                The most effective widgets display your application's most useful or timely +data in the smallest widget size. Users will weigh the usefulness or your widget +against the portion of the Home screen it covers, so the smaller the better.

                + +

                All widgets must fit within the bounding box of one of the six supported +widget sizes, or better yet, within a pair of portrait and landscape orientation +sizes, so your widget looks good when the user switches screen +orientations.

                + +

                Standard widget sizes illustrates the bounding +dimensions of the six widget sizes (three in portrait and three in landscape +orientation).

                + + +
              3. Select a matching frame.
              4. + +

                Standard widget frames illustrates the standard frames +for the six widget sizes, with links so you can download copies for your own +use. You don't have to use these frames for your widget, but if you do, your +widgets are more likely to fit visually with other widgets.

                + +
              5. Apply standard shadow effect to your graphics.
              6. + +

                Again, you don't have to use this effect, but Standard +widget shadows shows the Photoshop settings used for standard widgets.

                + +
              7. If your widget includes buttons, draw them in three states +(default, pressed, and selected).
              8. + +

                You can download a +Photoshop file that contains the three states of the Play button, taken from +the Music widget, to analyze the Photoshop settings used for the three standard +button effects.

                + +

                Click to download
+Photoshop template

                + +
              9. Finish drawing your artwork and then scale and align it to +fit.
              10. + +

                Widget alignment tips and tricks describes some +techniques for aligning your widget's graphics inside the standard frames, along +with a few other widget graphics tricks.

                + +
              11. Save your widget with the correct graphics file +settings.
              12. + +

                Windows graphics file format describes the correct +settings for your widget graphics files.

                + +
              + + +

              Standard widget sizes

              + +

              There are six standard widget sizes, based on a Home screen grid of 4 x 4 +(portrait) or 4 x 4 (landscape) cells. These dimensions are the bounding boxes +for the six standard widget sizes. The contents of typical widgets don't draw to +the edge of these dimensions, but fit inside a frame withing the bounding box, +as described in Designing a widget.

              + +

              In portrait orientation, each cell is 80 pixels wide by 100 pixels tall (the +diagram shows a cell in portrait orientation). The three supported widget sizes +in portrait orientation are:

              + +

        Comments
        userdata.img The initial user-data disk image
        + + + + +
        CellsPixels
        4 x 1320 x 100
        3 x 3240 x 300
        2 x 2160 x 200
        + +

        Widget
+dimensions in portrait orientation

        + +

        In landscape orientation, each cell is 106 pixels wide by 74 pixels tall. The +three supported widget sizes in landscape orientation are:

        + + + + + + +
        CellsPixels
        4 x 1424 x 74
        3 x 3318 x 222
        2 x 2212 x 148
        + +

        Widget
+dimensions in landscape orientation

        + + +

        Standard widget frames

        + +

        For each of the six standard widget sizes there is a standard frame. You can +click the images of the frames in this section to download a Photoshop file for +that frame, which you can use for your own widgets.

        + +

        Click to
+download
        4x1_Widget_Frame_Portrait.psd

        + +

        Click to
+download
        3x3_Widget_Frame_Portrait.psd

        + +

        Click to
+download
        2x2_Widget_Frame_Portrait.psd

        + +

        Click
+to download
        4x1_Widget_Frame_Landscape.psd

        + +

        Click
+to download
        3x3_Widget_Frame_Landscape.psd

        + +

        Click
+to download
        2x2_Widget_Frame_Landscape.psd

        + + +

        Standard widget shadows

        + +

        You can apply a shadow effect to your widget's artwork, so it matches other +standard Android widgets, using the following settings in the Photoshop Layer +Style dialog box.

        + +

        Layer Style
+settings for standard shadows

        + + +

        Widget graphics tips and tricks

        + +

        The Android team has developed a few tricks for aligning widget artwork +within standard widget bounding boxes and frames, so the widget aligns visually +with other widgets and the other elements of the Home screen, as well as other +techniques for creating widgets. + +

          + +
        • Use a screen shot from the Android SDK emulator to align both the shapes and +shadows of your widget controls with the Search widget and with other elements +on the Home screen.
        • + +

          Cut the widget artwork asset" based on the full size of a cell, including any +padding you want. (That is, for a 4 x 1 widget, cut the asset at 320 by 100 +pixels.)

          + +

          Aligning widget
+graphics

          + +
        • To reduce banding when exporting a widget, apply the following Photoshop Add +Noise setting to your graphic.
        • + +

          Add Noise
+settings for widget graphics

          + +
        • Apply 9-patch techniques to shrink the graphic and set the padding of the +content area. (See +the detailed guide here.)
        • + +

          Note: The current Android widget templates were designed +using a custom gradient angle, which means the 9-patch techniques can't be used +to optimize the size of the asset. However, 9-patch techniques were used to set +the content area padding.

          + +
        • In some cases, devices have low pixel depths that can cause visual banding +and dithering issues. To solve this, application developers should pass assets +through a "proxy" drawable defined as XML:. This +technique references the original artwork, in this case +"background.9.png", and instructs the device to dither it as +needed.
        • + +
        + +

        Widget graphics file format

        + +

        Save your widget artwork using the appropriate bounding box size in PNG-24 +format on a transparent background and in 8-bit color.

        + +

        Widget graphics file format

        + + + + + diff --git a/docs/html/guide/publishing/app-signing.jd b/docs/html/guide/publishing/app-signing.jd index 28c927aed29c5deaac5aa9f7cab08274eed6c6c6..a16c9106ad931f9dc5656756654d2a5144beace1 100644 --- a/docs/html/guide/publishing/app-signing.jd +++ b/docs/html/guide/publishing/app-signing.jd @@ -22,9 +22,10 @@ page.title=Signing Your Applications
      35. Signing in Debug Mode
      36. Signing for Public Release
          -
        1. Compiling for Release
        2. -
        3. Obtaining a Suitable Private Key
        4. -
        5. Signing Your Application
        6. +
        7. Compiling for release
        8. +
        9. Obtaining a suitable private key
        10. +
        11. Signing your application
        12. +
        13. Compiling and signing with Eclipse ADT
      37. Securing Your Private Key
      38. @@ -47,9 +48,9 @@ page.title=Signing Your Applications

        The Android system requires that all installed applications be digitally signed with a certificate whose private key is held by the application's -developer. The system uses the certificate as a means of identifying the author of -an application and establishing trust relationships between applications, rather -than for controlling which applications the user can install. The certificate +developer. The Android system uses the certificate as a means of identifying the author of +an application and establishing trust relationships between applications. The certificate is not +used to control which applications the user can install. The certificate does not need to be signed by a certificate authority: it is perfectly allowable, and typical, for Android applications to use self-signed certificates.

        @@ -61,8 +62,8 @@ certificates.

        that is not signed.
      39. You can use self-signed certificates to sign your applications. No certificate authority is needed.
      40. -
      41. When you are ready to publish your application, you must sign it with a suitable private -key. You can not publish an application that is signed with the default key generated +
      42. When you are ready to release your application for end-users, you must sign it with a suitable private +key. You can not publish an application that is signed with the debug key generated by the SDK tools.
      43. The system tests a signer certificate's expiration date only at install time. If an @@ -78,20 +79,32 @@ For this reason, you must set up signing for your application before you will be run or debug it on an emulator or device.

        The Android SDK tools assist you in signing your applications when debugging. Both the ADT Plugin -for Eclipse and the Ant build tool offer two signing modes — debug mode and release mode. +for Eclipse and the Ant build tool offer two signing modes — debug mode +and release mode.

          -
        • In debug mode, the build tools use the Keytool utility, included in the JDK, to create +
        • While developing and testing, you can compile in debug mode. +In debug mode, the build tools use the Keytool utility, included in the JDK, to create a keystore and key with a known alias and password. At each compilation, the tools then use the debug key to sign the application .apk file. Because the password is known, the tools don't need to prompt you for the keystore/key password each time you compile.
        • -
        • When your application is ready for release, you compile it in release signing mode. -In this mode, the tools compile your .apk without signing it. You must then sign -the .apk manually — with your private key — -using Jarsigner (or similar tool). If you do not have a suitable private key already, -you can run Keytool manually to generate your own keystore/key and then sign your -application with Jarsigner.
        • +
        • When your application is ready for release, you must compile in release mode +and then sign the .apk with your private key. +There are two ways to do this: +
            +
          • Using Keytool and Jarsigner in the command-line. In this approach, + you first compile your application to an unsigned .apk. You must then sign + the .apk manually with your private key + using Jarsigner (or similar tool). If you do not have a suitable private key already, + you can run Keytool manually to generate your own keystore/key and then sign your + application with Jarsigner.
          • +
          • Using the ADT Export Wizard. If you are developing in Eclipse with the ADT plugin, + you can use the Export Wizard to compile the application, generate a private key + (if necessary), and sign the .apk, all in a single process using the Export Wizard. +
          • +
          +

        Signing Strategies

        @@ -105,7 +118,7 @@ all of your applications with the same certificate, throughout the expected lifespan of your applications. There are several reasons why you should do so:

          -
        • Application upgrade — As you release upgrades to your +
        • Application upgrade – As you release upgrades to your application, you will want to sign the upgrades with the same certificate, if you want users to upgrade seamlessly to the new version. When the system is installing an update to an application, if any of the certificates in the @@ -115,13 +128,13 @@ certificate, you will also need to assign a different package name to the application — in this case, the user installs the new version as a completely new application.
        • -
        • Application modularity — The Android system allows applications that +
        • Application modularity – The Android system allows applications that are signed by the same certificate to run in the same process, if the -applications so request, so that the system treats them as a single application. +applications so requests, so that the system treats them as a single application. In this way you can deploy your application in modules, and users can update each of the modules independently if needed.
        • -
        • Code/data sharing through permissions — The Android system provides +
        • Code/data sharing through permissions – The Android system provides signature-based permissions enforcement, so that an application can expose functionality to another application that is signed with a specified certificate. By signing multiple applications with the same certificate and @@ -167,7 +180,7 @@ Alternatively, you can add the JDK version of Keytool to your PATH variable.

          If you are developing on a version of Linux that originally came with GNU Compiler for Java, make sure that the system is using the JDK version of Keytool, rather than the gcj version. If Keytool is already in your PATH, it might be pointing to a symlink at -/usr/bin/keytool. In this case, check the symlink target to make sure that it points +/usr/bin/keytool. In this case, check the symlink target to make sure that it points to the Keytool in the JDK.

          If you will release your application to the public, you will also need to have @@ -180,38 +193,46 @@ in the JDK.

          to develop and debug your application, while still meeting the Android system requirement for signing your .apk when it is installed in the emulator or a device. When you use debug mode, the SDK tools invoke Keytool to create a debug -keystore and key.

          +keystore and key.

          The SDK tools create the debug keystore/key with predetermined names/passwords;

            -
          • Keystore name — "debug.keystore"
          • -
          • Keystore password — "android"
          • -
          • Key alias — "androiddebugkey"
          • -
          • Key password — "android"
          • -
          • CN — "CN=Android Debug,O=Android,C=US"
          • +
          • Keystore name – "debug.keystore"
          • +
          • Keystore password – "android"
          • +
          • Key alias – "androiddebugkey"
          • +
          • Key password – "android"
          • +
          • CN – "CN=Android Debug,O=Android,C=US"

          +

          If necessary, you can change the location/name of the debug keystore/key or +supply a custom debug keystore/key to use. In Eclipse/ADT, you can use +Windows > Prefs > +Android > Build. However, any custom debug +keystore/key must use the same keystore/key names and passwords as the default +debug key (as described above).

          + +

          Note: You cannot release your application +to the public when signed with the debug certificate.

          + +

          Eclipse Users

          +

          If you are developing in Eclipse/ADT and have set up Keytool as described above, signing in debug mode is enabled by default. When you run or debug your application, ADT signs the .apk with the debug certificate and installs it on the emulator. No specific action on your part is needed, provided ADT has access to Keytool.

          +

          Ant Users

          +

          If you use Ant to build your .apk files, debug signing mode -is enabled by default, assuming that you are using a build.xml file generated by the -activitycreator tool included in the latest SDK. When you run Ant against build.xml to +is enabled by using the debug option, assuming that you are using a +build.xml file generated by the +android tool. When you run ant debug to compile your app, the build script generates a keystore/key and signs the .apk for you. -No specific action on your part is needed.

          - -

          If necessary, you can change the location/name of the debug keystore/key or -supply a custom debug keystore/key to use. In Eclipse/ADT, you can use -Windows > Prefs > -Android > Build. However, any custom debug -keystore/key must use the same keystore/key names and passwords as the default -debug key (as described above).

          +No other action on your part is needed. Read +Developing In Other IDEs: Building +in debug mode for more information.

          -

          Note that you cannot release your application to the public if it -is signed with the debug certificate.

          Expiry of the Debug Certificate

          @@ -227,11 +248,11 @@ looks like this:

          In Eclipse/ADT, you will see a similar error in the Android console.

          -

          To fix this problem, simply delete the debug.keystore file. On Linux/Mac OSX, -the file is stored in ~/.android. On Windows XP, the file is stored in -C:\Documents and Settings\<user>\Local Settings\Application Data\Android. -On Windows Vista, the file is stored in -C:\Users\<user>\AppData\Local\Android.

          +

          To fix this problem, simply delete the debug.keystore file. +The default storage location for AVDs is in ~/.android/avd on OS X and Linux, +in C:\Documents and Settings\\.android\ on Windows XP, and in +C:\Users\\.android\ on Windows Vista.

          +

          The next time you build, the build tools will regenerate a new keystore and debug key.

          @@ -242,29 +263,45 @@ troubleshooting topic Signing for Public Release

          When your application is ready for release to other users, you must:

            -
          1. Compile the application in release mode
          2. -
          3. Obtain a suitable private key, and then
          4. -
          5. Sign the application with your private key
          6. -
          7. Secure your private key
          8. +
          9. Compile the application in release mode
          10. +
          11. Obtain a suitable private key
          12. +
          13. Sign the application with your private key
          -

          The sections below provide information about these steps.

          +

          The sections below provide information about how to perform these steps.

          + +

          If you use Eclipse with the ADT plugin, you can instead use the Export Wizard +to compile and sign an .apk with your private key. The Export Wizard even allows you to +generate a new keystore and private key in the process. Skip to +Compiling and signing with Eclipse ADT.

          + -

          Compiling for Release

          +

          Compiling for release

          To prepare your application for release, you must first compile it in release mode. In release mode, the Android build tools compile your application as usual, -but without signing it with the debug key.

          +but without signing it with the debug key.

          + +

          Note: +You can not release your application unsigned, or signed with the debug key.

          + +

          Eclipse users

          + +

          To export an unsigned .apk from Eclipse, right-click the project in the Package +Explorer and select Android Tools > Export Unsigned Application +Package. Then simply specify the file location for the unsigned .apk. +(Alternatively, open your AndroidManifest.xml file in Eclipse, open +the Overview tab, and click Export an unsigned .apk.)

          + +

          You can also combine the compiling and signing steps with the Export Wizard. See +Compiling and signing with Eclipse ADT.

          -

          If you are developing in Eclipse/ADT, right-click the project in the Package -pane and select Android Tools > Export Application -Package. You can then specify the file location for the unsigned .apk. -Alternatively, you can follow the "Exporting the unsigned .apk" -link in the Manifest Editor overview page.

          +

          Ant users

          If you are using Ant, all you need to do is specify the build target "release" in the Ant command. For example, if you are running Ant from the @@ -272,9 +309,8 @@ directory containing your build.xml file, the command would look like this:

          $ ant release
          -

          The build script compiles the application .apk without signing it. +

          The build script compiles the application .apk without signing it.

          -

          Note that you can not release your application unsigned, or signed with the debug key.

          Obtaining a Suitable Private Key

          @@ -303,7 +339,7 @@ in Basic Setup.

          command and pass any of the options listed below (and any others, as needed).

          -

          Before you run Keytool, make sure to read +

          Note: Before you run Keytool, make sure to read Securing Your Private Key for a discussion of how to keep your key secure and why doing so is critically important to you and to users. In particular, when you are generating your key, you should select strong passwords @@ -378,7 +414,8 @@ will use later, to refer to this keystore when signing your application.

          href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security"> http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security

          -

          Signing Your Application

          + +

          Signing your application

          When you are ready to actually sign your .apk for release, you can do so using the Jarsigner tool. Make sure that you have Jarsigner available on your @@ -425,9 +462,9 @@ way, your password is not stored in your shell history.

          my_application.apk alias_name

          Running the example command above, Jarsigner prompts you to provide -passwords for the keystore and key. It then modifies the APK +passwords for the keystore and key. It then modifies the .apk in-place, meaning the .apk is now signed. Note that you can sign an -APK multiple times with different keys.

          +.apk multiple times with different keys.

          To verify that your .apk is signed, you can use a command like this:

          @@ -445,7 +482,7 @@ If you want more details, you can try one of these commands:

          The command above, with the -certs option added, will show you the "CN=" line that describes who created the key.

          -

          Note: if you see "CN=Android Debug", this means the .apk was +

          Note: If you see "CN=Android Debug", this means the .apk was signed with the debug key generated by the Android SDK. If you intend to release your application, you must sign it with your private key instead of the debug key.

          @@ -454,6 +491,32 @@ key.

          http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security

          + +

          Compiling and signing with Eclipse ADT

          + +

          When using Eclipse with ADT, you can use the Export Wizard to +export a signed .apk (and even create a new keystore, +if necessary). The Export Wizard performs all the interaction with +the Keytool and Jarsigner for you, which allows you to perform signing via a +graphical interface instead of the command-line. +Because the Export Wizard uses both Keytool and Jarsigner, you should +ensure that they are accessible on your computer, as described above +in the Basic Setup for Signing.

          + +

          To create a signed .apk, right-click the project in the Package +Explorer and select Android Tools > Export Signed Application Package. +(Alternatively, open your AndroidManifest.xml file in Eclipse, open +the Overview tab, and click Use the Export Wizard.) +The window that appears will display any errors found while +attempting to export your application. If no errors are found, continue with the +Export Wizard, which will guide you through the process of signing your application, +including steps for selecting the private key with which to sign the .apk, +or creating a new keystore and private key.

          + +

          When you complete the Export Wizard, you'll +have a signed .apk that's ready for distribution.

          + +

          Securing Your Private Key

          Maintaining the security of your private key is of critical importance, both diff --git a/docs/html/guide/publishing/preparing.jd b/docs/html/guide/publishing/preparing.jd index d355265efb68e92a9b33d7cee6745932e36a9792..b4eaea39607ff9e9c1006c8e7efcad4c3f90c92e 100644 --- a/docs/html/guide/publishing/preparing.jd +++ b/docs/html/guide/publishing/preparing.jd @@ -178,8 +178,8 @@ MapView elements

          +href="http://code.google.com/android/add-ons/google-apis/mapkey.html"> +Obtaining a Maps API Key.

      If your application uses one or more Mapview elements, you will need to register your application with the Google @@ -221,7 +221,7 @@ to download Maps data.

    For more information about signing and your private key, see Signing Your Applications.

    +href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications.

    Compile your application

    @@ -234,7 +234,8 @@ you can compile your application for release.

    8. Sign your application

    Sign your application using your private key. Signing your application -correctly is critically important. Please see Signing Your +correctly is critically important. Please see +Signing Your Applications for complete information.

    9. Test your compiled and signed application

    diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd index 4e665fa500cc6655aae9a5f0f1305ab0ac792040..365284d45bab8ecc2d3cfdabf1968adfc154610c 100644 --- a/docs/html/guide/samples/index.jd +++ b/docs/html/guide/samples/index.jd @@ -4,11 +4,13 @@ page.title=Sample Code

    Sometimes, the best way to learn how things are done is to just look at some code. So here - we've provided links to let you browse the source of some some simple Android applications.

    + we've provided links to let you browse the source of some sample Android applications included +in the Android SDK.

    -

    The source code for these applications is included in the Android SDK, in this location:

    +

    The SDK includes a full set of sample applications for each Android platform version +in the SDK. You can find the sample applications for each platform version in this location:

    -

    <sdk>/samples/

    +

    <sdk>/platforms/android-<version>/samples/

    You can easily add these applications as projects in your development environment, so that you can modify them and watch them execute.

    diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..01a96484e4183f8acf48e6ee458dde5576d5a0d5 --- /dev/null +++ b/docs/html/guide/topics/appwidgets/index.jd @@ -0,0 +1,463 @@ +page.title=App Widgets +@jd:body + + + + +

    App Widgets are miniature application views that can be embedded in other applications +(such as the Home screen) and receive periodic updates. These views are referred +to as Widgets in the user interface, +and you can publish one with an App Widget provider. An application component that is +able to hold other App Widgets is called an App Widget host. The screenshot below shows +the Music App Widget.

    + + + +

    This document describes how to publish an App Widget using an App Widget provider.

    + + +

    The Basics

    + +

    To create an App Widget, you need the following:

    + +
    +
    {@link android.appwidget.AppWidgetProviderInfo} object
    +
    Describes the metadata for an App Widget, such as the App Widget's layout, update frequency, + and the AppWidgetProvider class. This should be defined in XML.
    +
    {@link android.appwidget.AppWidgetProvider} class implementation
    +
    Defines the basic methods that allow you to programmatically interface with the App Widget, + based on broadcast events. Through it, you will receive broadcasts when the App Widget is updated, + enabled, disabled and deleted.
    +
    View layout
    +
    Defines the initial layout for the App Widget, defined in XML.
    +
    + +

    Additionally, you can implement an App Widget configuration Activity. This is an optional +{@link android.app.Activity} that launches when the user adds your App Widget and allows him or her +to modify App Widget settings at create-time.

    + +

    The following sections describe how to setup each of these components.

    + + +

    Declaring an App Widget in the Manifest

    + +

    First, declare the {@link android.appwidget.AppWidgetProvider} class in your application's +AndroidManifest.xml file. For example:

    + +
    +<receiver android:name="ExampleAppWidgetProvider" >
    +    <intent-filter>
    +        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    +    </intent-filter>
    +    <meta-data android:name="android.appwidget.provider"
    +               android:resource="@xml/example_appwidget_info" />
    +</receiver>
    +
    + +

    The <receiver> element requires the android:name +attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used +by the App Widget.

    + +

    The <intent-filter> element must include an <action> +element with the android:name attribute. This attribute specifies +that the {@link android.appwidget.AppWidgetProvider} accepts the {@link +android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE ACTION_APPWIDGET_UPDATE} broadcast. +This is the only broadcast that you must explicitly declare. The {@link android.appwidget.AppWidgetManager} +automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.

    + +

    The <meta-data> element specifies the +{@link android.appwidget.AppWidgetProviderInfo} resource and requires the +following attributes:

    +
      +
    • android:name - Specifies the metadata name. Use android.appwidget.provider + to identify the data as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.
    • +
    • android:resource - Specifies the {@link android.appwidget.AppWidgetProviderInfo} + resource location.
    • +
    + + +

    Adding the AppWidgetProviderInfo Metadata

    + +

    The {@link android.appwidget.AppWidgetProviderInfo} defines the essential +qualities of an App Widget, such as its minimum layout dimensions, its initial layout resource, +how often to update the App Widget, and (optionally) a configuration Activity to launch at create-time. +Define the AppWidgetProviderInfo object in an XML resource using a single +<appwidget-provider> element and save it in the project's res/xml/ +folder.

    + +

    For example:

    + +
    +<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:minWidth="294dp" <!-- density-independent pixels -->
    +    android:minHeight="72dp"
    +    android:updatePeriodMillis="86400000" <!-- once per day -->
    +    android:initialLayout="@layout/example_appwidget"
    +    android:configure="com.example.android.ExampleAppWidgetConfigure" >
    +</appwidget-provider>
    +
    + +

    Here's a summary of the <appwidget-provider> attributes:

    +
      +
    • The values for the minWidth and minHeight attributes specify the minimum + area required by the App Widget's layout. +

      The default Home screen positions App Widgets in its window based on a grid of + cells that have a defined height and width. If the values for an App Widget's minimum width + or height don't match the dimensions of the cells, + then the App Widget dimensions round up to the nearest cell size. + (See the App Widget Design + Guidelines for more information on the Home screen cell sizes.)

      +

      Because the Home screen's layout orientation (and thus, the cell sizes) can change, + as a rule of thumb, you should assume the worst-case cell size of 74 pixels for the height + and width of a cell. However, you must subtract 2 from the final dimension to account + for any integer rounding errors that occur in the pixel count. To find your minimum width + and height in density-independent pixels (dp), use this formula:
      + (number of cells * 74) - 2
      + Following this formula, you should use 72 dp for a height of one cell, 294 dp and for a width of four cells.

      +
    • +
    • The updatePerdiodMillis attribute defines how often the App Widget framework should + request an update from the {@link android.appwidget.AppWidgetProvider} by calling the + {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) + onUpdate()} method. The actual update is not guaranteed to occur exactly on time with this value + and we suggest updating as infrequently as possible—perhaps no more than once an hour to + conserve the battery. You might also allow the user to adjust the frequency in a + configuration—some people might want a stock ticker to update every 15 minutes, or maybe + only four times a day.
    • +
    • The initialLayout attribute points to the layout resource that defines the + App Widget layout.
    • +
    • The configure attribute defines the {@link android.app.Activity} to launch when + the user adds the App Widget, in order for him or her to configure App Widget properties. This is optional + (read Creating an App Widget Configuration Activity below).
    • +
    + +

    See the {@link android.appwidget.AppWidgetProviderInfo} class for more information on the +attributes accepted by the <appwidget-provider> element.

    + + +

    Creating the App Widget Layout

    + +

    You must define an initial layout for your App Widget in XML and save it in the project's +res/layout/ directory. You can design your App Widget using the View objects listed +below, but before you begin designing your App Widget, please read and understand the +App Widget Design +Guidelines.

    + +

    Creating the App Widget layout is simple if you're +familiar with Declaring Layout in XML. +However, you must be aware that App Widget layouts are based on {@link android.widget.RemoteViews}, +which do not support every kind of layout or view widget.

    + +

    A RemoteViews object (and, consequently, an App Widget) can support the +following layout classes:

    + +
      +
    • {@link android.widget.FrameLayout}
    • +
    • {@link android.widget.LinearLayout}
    • +
    • {@link android.widget.RelativeLayout}
    • +
    + +

    And the following widget classes:

    +
      +
    • {@link android.widget.AnalogClock}
    • +
    • {@link android.widget.Button}
    • +
    • {@link android.widget.Chronometer}
    • +
    • {@link android.widget.ImageButton}
    • +
    • {@link android.widget.ImageView}
    • +
    • {@link android.widget.ProgressBar}
    • +
    • {@link android.widget.TextView}
    • +
    + +

    Descendants of these classes are not supported.

    + + +

    Using the AppWidgetProvider Class

    + + + +

    The {@link android.appwidget.AppWidgetProvider} class extends BroadcastReceiver as a convenience +class to handle the App Widget broadcasts. The AppWidgetProvider receives only the event broadcasts that +are relevant to the App Widget, such as when the App Widget is updated, deleted, enabled, and disabled. +When these broadcast events occur, the AppWidgetProvider receives the following method calls:

    + +
    +
    {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])}
    +
    This is called to update the App Widget at intervals defined by the updatePeriodMillis + attribute in the AppWidgetProviderInfo (see Adding the + AppWidgetProviderInfo Metadata above). This method is also called + when the user adds the App Widget, so it should perform the essential setup, + such as define event handlers for Views and start a temporary + {@link android.app.Service}, if necessary. However, if you have declared a configuration + Activity, this method is not called when the user adds the App Widget, + but is called for the subsequent updates. It is the responsibility of the + configuration Activity to perform the first update when configuration is done. + (See Creating an App Widget Configuration Activity below.)
    +
    {@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}
    +
    This is called every time an App Widget is deleted from the App Widget host.
    +
    {@link android.appwidget.AppWidgetProvider#onEnabled(Context)}
    +
    This is called when an instance the App Widget is created for the first time. For example, if the user + adds two instances of your App Widget, this is only called the first time. + If you need to open a new database or perform other setup that only needs to occur once + for all App Widget instances, then this is a good place to do it.
    +
    {@link android.appwidget.AppWidgetProvider#onDisabled(Context)}
    +
    This is called when the last instance of your App Widget is deleted from the App Widget host. + This is where you should clean up any work done in + {@link android.appwidget.AppWidgetProvider#onEnabled(Context)}, + such as delete a temporary database.
    +
    {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}
    +
    This is called for every broadcast and before each of the above callback methods. + You normally don't need to implement this method because the default AppWidgetProvider + implementation filters all App Widget broadcasts and calls the above + methods as appropriate.
    +
    + +

    Note: In Android 1.5, there is a known issue in which the +onDeleted() method will not be called when it should be. To work around this issue, +you can implement {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent) +onReceive()} as described in this +Group post +to receive the onDeleted() callback. +

    + +

    The most important AppWidgetProvider callback is +{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) +onUpdated()} because it is called when each App Widget is added to a host (unless you use +a configuration Activity). If your App Widget accepts any +user interaction events, then you need to register the event handlers in this callback. +If your App Widget doesn't create temporary +files or databases, or perform other work that requires clean-up, then +{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) +onUpdated()} may be the only callback method you need to define. For example, if you want an App Widget +with a button that launches an Activity when clicked, you could use the following +implementation of AppWidgetProvider:

    + +
    +public class ExampleAppWidgetProvider extends AppWidgetProvider {
    +
    +    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    +        final int N = appWidgetIds.length;
    +
    +        // Perform this loop procedure for each App Widget that belongs to this provider
    +        for (int i=0; i<N; i++) {
    +            int appWidgetId = appWidgetIds[i];
    +
    +            // Create an Intent to launch ExampleActivity
    +            Intent intent = new Intent(context, ExampleActivity.class);
    +            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
    +
    +            // Get the layout for the App Widget and attach an on-click listener to the button
    +            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
    +            views.setOnClickPendingIntent(R.id.button, pendingIntent);
    +
    +            // Tell the AppWidgetManager to perform an update on the current App Widget
    +            appWidgetManager.updateAppWidget(appWidgetId, views);
    +        }
    +    }
    +}
    +
    + +

    This AppWidgetProvider defines only the +{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) +onUpdated()} method for the purpose +of defining a {@link android.app.PendingIntent} that launches an {@link android.app.Activity} +and attaching it to the App Widget's button +with {@link android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. +Notice that it includes a loop that iterates through each entry in appWidgetIds, which +is an array of IDs that identify each App Widget created by this provider. +In this way, if the user creates more than one instance of the App Widget, then they are +all updated simultaneously. However, only one updatePeriodMillis schedule will be +managed for all instances of the App Widget. For example, if the update schedule is defined +to be every two hours, and a second instance +of the App Widget is added one hour after the first one, then they will both be updated +on the period defined by the first one and the second update period will be ignored +(they'll both be updated every two hours, not every hour).

    + +

    Note: Because the AppWidgetProvider is a BroadcastReceiver, +your process is not guaranteed to keep running after the callback methods return (see +Application Fundamentals > +Broadcast Receiver Lifecycle for more information). If your App Widget setup process can take several +seconds (perhaps while performing web requests) and you require that your process continues, +consider starting a {@link android.app.Service} +in the {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) +onUpdated()} method. From within the Service, you can perform your own updates to the App Widget +without worrying about the AppWidgetProvider closing down due to an +Application Not Responding +(ANR) error. See the +Wiktionary +sample's AppWidgetProvider for an example of an App Widget running a {@link android.app.Service}.

    + +

    Also see the +ExampleAppWidgetProvider.java sample class.

    + + +

    Receiving App Widget broadcast Intents

    + +

    {@link android.appwidget.AppWidgetProvider} is just a convenience class. If you would like +to receive the App Widget broadcasts directly, you can implement your own +{@link android.content.BroadcastReceiver} or override the +{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback. +The four Intents you need to care about are:

    +
      +
    • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}
    • +
    • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}
    • +
    • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}
    • +
    • {@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}
    • +
    + + + +

    Creating an App Widget Configuration Activity

    + +

    If you would like the user to configure settings when he or she adds a new App Widget, +you can create an App Widget configuration Activity. This {@link android.app.Activity} +will be automatically launched by the App Widget host and allows the user to configure +available settings for the App Widget at create-time, such as the App Widget color, size, +update period or other functionality settings.

    + +

    The configuration Activity should be declared as a normal Activity in the Android manifest file. +However, it will be launched by the App Widget host with the {@link +android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE ACTION_APPWIDGET_CONFIGURE} action, +so the Activity needs to accept this Intent. For example:

    + +
    +<activity android:name=".ExampleAppWidgetConfigure">
    +    <intent-filter>
    +        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
    +    </intent-filter>
    +</activity>
    +
    + +

    Also, the Activity must be declared in the AppWidgetProviderInfo XML file, with the +android:configure attribute (see Adding +the AppWidgetProvierInfo Metadata above). For example, the configuration Activity +can be declared like this:

    + +
    +<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    +    ...
    +    android:configure="com.example.android.ExampleAppWidgetConfigure" 
    +    ... >
    +</appwidget-provider>
    +
    + +

    Notice that the Activity is declared with a fully-qualified namespace, because +it will be referenced from outside your package scope.

    + +

    That's all you need to get started with a configuration Activity. Now all you need is the actual +Activity. There are, however, two important things to remember when you implement the Activity:

    +
      +
    • The App Widget host calls the configuration Activity and the configuration Activity should always + return a result. The result should include the App Widget ID + passed by the Intent that launched the Activity (saved in the Intent extras as + {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).
    • +
    • The {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) + onUpdate()} method will not be called when the App Widget is created + (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration Activity + is launched). It is the responsibility of the configuration Activity to request an update from the + AppWidgetManager when the App Widget is first created. However, + {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) + onUpdate()} will be called for subsequent updates—it is only skipped the first time.
    • +
    + +

    See the code snippets in the following section for an example of how to return a result +from the configuration and update the App Widget.

    + + +

    Updating the App Widget from the configuration Activity

    + +

    When an App Widget uses a configuration Activity, it is the responsibility of the Activity +to update the App Widget when configuration is complete. +You can do so by requesting an update directly from the +{@link android.appwidget.AppWidgetManager}.

    + +

    Here's a summary of the procedure to properly update the App Widget and close +the configuration Activity:

    + +
      +
    1. First, get the App Widget ID from the Intent that launched the Activity: +
      +Intent intent = getIntent();
      +Bundle extras = intent.getExtras();
      +if (extras != null) {
      +    mAppWidgetId = extras.getInt(
      +            AppWidgetManager.EXTRA_APPWIDGET_ID, 
      +            AppWidgetManager.INVALID_APPWIDGET_ID);
      +}
      +
      +
    2. +
    3. Perform your App Widget configuration.
    4. +
    5. When the configuration is complete, get an instance of the AppWidgetManager by calling + {@link android.appwidget.AppWidgetManager#getInstance(Context)}: +
      +AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
      +
      +
    6. +
    7. Update the App Widget with a {@link android.widget.RemoteViews} layout by calling + {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}: +
      +RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
      +appWidgetManager.updateAppWidget(mAppWidgetId, views);
      +
      +
    8. +
    9. Finally, create the return Intent, set it with the Activity result, and finish the Activity:
    10. +
      +Intent resultValue = new Intent();
      +resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
      +setResult(RESULT_OK, resultValue);
      +finish();
      +
      + +
    + +

    Tip: When your configuration Activity first opens, set +the Activity result to RESULT_CANCELED. This way, if the user backs-out of the Activity before +reaching the end, the App Widget host is notified that the configuration was cancelled and the +App Widget will not be added.

    + +

    See the +ExampleAppWidgetConfigure.java sample class in ApiDemos for an example.

    + + + diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd index 3c7f419713f87b8a9531960b062e6c86842e382e..71705d354f622c3766d1b32807a2c3ead812f085 100644 --- a/docs/html/guide/topics/fundamentals.jd +++ b/docs/html/guide/topics/fundamentals.jd @@ -464,7 +464,7 @@ two intent filters to the activity: </intent-filter> <intent-filter . . . > <action android:name="com.example.project.BOUNCE" /> - <data android:type="image/jpeg" /> + <data android:mimeType="image/jpeg" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> diff --git a/docs/html/guide/topics/geo/lbs.jd b/docs/html/guide/topics/geo/lbs.jd deleted file mode 100644 index 981f6fe9b3ba6f76dc170413ae450cd22333f958..0000000000000000000000000000000000000000 --- a/docs/html/guide/topics/geo/lbs.jd +++ /dev/null @@ -1,73 +0,0 @@ -page.title=Location-based Service APIs -@jd:body - -

    The Android SDK includes two packages that provide Android's primary support -for building location-based services: -{@link android.location} and com.google.android.maps. -Please read on below for a brief introduction to each package.

    - -

    android.location

    - -

    This package contains several classes related to -location services in the Android platform. Most importantly, it introduces the -{@link android.location.LocationManager} -service, which provides an API to determine location and bearing if the -underlying device (if it supports the service). The LocationManager -should not be -instantiated directly; rather, a handle to it should be retrieved via -{@link android.content.Context#getSystemService(String) -getSystemService(Context.LOCATION_SERVICE)}.

    - -

    Once your application has a handle to the LocationManager, your application -will be able to do three things:

    - -
      -
    • Query for the list of all LocationProviders known to the - LocationManager for its last known location.
    • -
    • Register/unregister for periodic updates of current location from a - LocationProvider (specified either by Criteria or name).
    • -
    • Register/unregister for a given Intent to be fired if the device comes - within a given proximity (specified by radius in meters) of a given - lat/long.
    • -
    - -

    However, during initial development, you may not have access to real -data from a real location provider (Network or GPS). So it may be necessary to -spoof some data for your application, with some mock location data.

    - -

    Note: If you've used mock LocationProviders in -previous versions of the SDK (m3/m5), you can no longer provide canned LocationProviders -in the /system/etc/location directory. These directories will be wiped during boot-up. -Please follow the new procedures below.

    - - -

    Providing Mock Location Data

    - -

    When testing your application on the Android emulator, there are a couple different -ways to send it some spoof location data: with the DDMS tool or the "geo" command.

    - -

    Using DDMS

    -

    With the DDMS tool, you can simulate location data a few different ways:

    -
      -
    • Manually send individual longitude/latitude coordinates to the device.
    • -
    • Use a GPX file describing a route for playback to the device.
    • -
    • Use a KML file describing individual placemarks for sequenced playback to the device.
    • -
    -

    For more information on using DDMS to spoof location data, see the -Using DDMS guide. - -

    Using the "geo" command

    -

    Launch your application in the Android emulator and open a terminal/console in -your SDK's /tools directory. Now you can use:

    -
    • geo fix to send a fixed geo-location. -

      This command accepts a longitude and latitude in decimal degrees, and - an optional altitude in meters. For example:

      -
      geo fix -121.45356 46.51119 4392
      -
    • -
    • geo nmea to send an NMEA 0183 sentence. -

      This command accepts a single NMEA sentence of type '$GPGGA' (fix data) or '$GPRMC' (transit data). - For example:

      -
      geo nmea $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
      -
    • -
    - diff --git a/docs/html/guide/topics/geo/mapkey.jd b/docs/html/guide/topics/geo/mapkey.jd deleted file mode 100644 index 64429406d6e148a532d0170f11ac566bc889ee07..0000000000000000000000000000000000000000 --- a/docs/html/guide/topics/geo/mapkey.jd +++ /dev/null @@ -1,28 +0,0 @@ -page.title=Obtaining a MapView API Key -@jd:body - -

    MapView is a very useful class that lets you easily integrate Google Maps into your application. It provides built-in map downloading, rendering, and caching, as well as a variety of display options and controls. It provides a wrapper around the Google Maps API that lets your application request and manipulate Google Maps data through class methods, and it lets you work with Maps data as you would other types of Views.

    - -

    Because MapView gives you access to Google Maps data, you need to register your application with the Google Maps service and agree to the applicable Terms of Service, before your MapView will be able to obtain data from Google Maps. This will apply whether you are developing your application on the emulator or preparing your application for deployment to mobile devices.

    - -

    Registering your application is simple, and has two parts:

    - -
      -
    1. Registering a public key fingerprint from the certificate that you will use to sign the .apk. The registration service then provides you a Maps API Key that is associated with your application's signer certificate.
    2. -
    3. Adding the Maps API Key to a special attribute of the MapView element — android:apiKey. You can use the same Maps API Key for any MapView in any application, provided that the application's .apk is signed with the certificate whose fingerprint you registered with the service.
    4. -
    - -

    Once you have registered your application as described above, your MapView will be able to retrieve data from the Google Maps servers.

    - -
    -

    The MapView registration service is not yet active and Google Maps is not yet enforcing the Maps API Key requirement. The registration service will be activated soon, so that MapViews in any application deployed to a mobile device will require registration and a valid Maps API Key.

    - -

    As soon as the registration service becomes available, this page (http://code.google.com/android/toolbox/apis/mapkey.html) will be updated with details about how and where to register and how to add your Maps API Key to your application.

    - -

    In the meantime, you can continue developing your MapView without registration, provided that you:

    -
      -
    1. Add the attribute "android:apiKey" to the MapView element in your layout XML, with any value. Or
    2. -
    3. Include an arbitrary string in the apikey parameter of the MapView constructor, if creating the MapView programmatically.
    4. -
    - -

    When the Maps API Key checking is activated in the service, any MapViews that do not have a properly registered apiKey will stop working. The map data (tile images) of the MapView will never load (even if the device is on the network). In this case, go to the page linked above and read about how to register your certificate fingerprint and obtain a Maps API Key.

    diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd index 1f62f3d0f367286ca34eec3cde1330ea0f01c832..af584a23fbe5badec733cfa89968a7a470ecb34c 100644 --- a/docs/html/guide/topics/graphics/2d-graphics.jd +++ b/docs/html/guide/topics/graphics/2d-graphics.jd @@ -10,8 +10,8 @@ parent.link=index.html
    1. Drawables
        -
      1. Creating from resource images
      2. -
      3. Creating from resource XML
      4. +
      5. Creating from resource images
      6. +
      7. Creating from resource XML
    2. ShapeDrawable
    3. @@ -59,6 +59,15 @@ From there, you can reference it from your code or your XML layout. Either way, it is referred using a resource ID, which is the file name without the file type extension (E.g., my_image.png is referenced as my_image).

      +

      Note: Image resources placed in res/drawable/ may be +automatically optimized with lossless image compression by the +aapt tool. For example, a true-color PNG that does +not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This +will result in an image of equal quality but which requires less memory. So be aware that the +image binaries placed in this directory can change during the build. If you plan on reading +an image as a bit stream in order to convert it to a bitmap, put your images in the res/raw/ +folder instead, where they will not be optimized.

      +

      Example code

      The following code snippet demonstrates how to build an {@link android.widget.ImageView} that uses an image from drawable resources and add it to the layout.

      @@ -90,7 +99,7 @@ Resources res = mContext.getResources(); Drawable myImage = res.getDrawable(R.drawable.my_image); -

      Caution: Each unique resource in your project can maintain only one +

      Note: Each unique resource in your project can maintain only one state, no matter how many different objects you may instantiate for it. For example, if you instantiate two Drawable objects from the same image resource, then change a property (such as the alpha) for one of the Drawables, then it will also affect the other. So when dealing with multiple instances of an image resource, diff --git a/docs/html/guide/topics/graphics/opengl.jd b/docs/html/guide/topics/graphics/opengl.jd index eb2932dfc835cc46c9fac6b81a64900f99bb1e89..901980d00e5869c43165f3e87f5c1f266f1279b3 100644 --- a/docs/html/guide/topics/graphics/opengl.jd +++ b/docs/html/guide/topics/graphics/opengl.jd @@ -26,10 +26,7 @@ ES API. However, it may not be identical, so watch out for deviations.

    4. In your View's onDraw() method, get a handle to a GL object, and use its methods to perform GL operations.
    -

    For an example of this usage model (based on the classic GL ColorCube), -see -com.android.samples.graphics.GLSurfaceView.java -in the ApiDemos sample code project. A slightly more sophisticated version showing how to use +

    For an example of this usage model (based on the classic GL ColorCube), showing how to use it with threads can be found in com.android.samples.graphics.GLSurfaceViewActivity.java.

    diff --git a/docs/html/guide/topics/location/geo/mapkey.jd b/docs/html/guide/topics/location/geo/mapkey.jd deleted file mode 100644 index 9aa824c1d61bb40ed13fa1770841768223f4ff36..0000000000000000000000000000000000000000 --- a/docs/html/guide/topics/location/geo/mapkey.jd +++ /dev/null @@ -1,210 +0,0 @@ -page.title=Obtaining a Maps API Key -@jd:body - - - -

    com.google.android.maps.MapView is a very useful class that lets you easily integrate Google Maps into your application. It provides built-in map downloading, rendering, and caching of Maps tiles, as well as a variety of display options and controls. It provides a wrapper around the Google Maps API that lets your application request and manipulate Google Maps data through class methods, and it lets you work with Maps data as you would other types of Views.

    - -

    Because MapView gives you access to Google Maps data, you need to register with the Google Maps service and agree to the applicable Terms of Service before your MapView will be able to obtain data from Google Maps. This will apply whether you are developing your application on the emulator or preparing your application for deployment to mobile devices.

    - -

    Registering for a Maps API Key is simple, free, and has two parts:

    - -
      -
    1. Registering the MD5 fingerprint of the certificate that you will use to sign your application. The Maps registration service then provides you a Maps API Key that is associated with your application's signer certificate.
    2. -
    3. Adding a reference to the Maps API Key in each MapView, whether declared in XML or instantiated directly from code. You can use the same Maps API Key for any MapView in any Android application, provided that the application is signed with the certificate whose fingerprint you registered with the service.
    4. -
    - -

    During registration, you also need to agree to the Maps API Terms of Service, which describe how your application can use the Maps data. In general, the terms of service are permissive and place few restrictions on how you can use the data. For example, the terms allow you to build "friend finder" type applications.

    - -

    The sections below describe how to obtain your Maps API Key and how to reference it from your MapView elements.

    - - - -

    Overview

    - -

    MapView objects are views that display Maps tiles downloaded from the Google Maps service. To ensure that applications use Maps data in an appropriate manner, the Google Maps service requires application developers to register with the service, agreeing to the Terms of Service and supplying an MD5 fingerprint of the certificate(s) that they will use to sign applications. For each registered certificate fingerprint, the service then provides the developer with a Maps API Key — an alphanumeric string that uniquely identifies the certificate and developer registered with the service.

    - -

    The Google Maps service also requires that each MapView identify itself to the service using a Maps API Key. Before providing Maps tiles to a MapView, the service checks the Maps API Key supplied by the MapView to ensure that it:

    -
      -
    • References a certificate/developer registered with the service, and
    • -
    • References a certificate that matches the certificate with which the application (containing the MapView) was signed.
    • -
    - -

    Unless both conditions are met, the service does not provide Maps tiles to the MapView.

    - -

    Each MapView object in your application must reference a Maps API Key. Since the Key is associated with a certificate, all Mapview elements in an application should reference the same Key. Going a step further, all MapView elements in all applications that you sign with the same certificate should reference the same Key.

    - -

    On the other hand, you can register for multiple Maps API Keys, each being associated with a specific certificate. You would want to do this if, for example, you were developing several independent applications that you will sign using different certificates. In this case, note that all MapView elements in a given application can reference the same Maps API Key, but must reference the Key that is associated with the certificate used to sign the application.

    - -

    Because MapView elements must refer to a Maps API Key, you need to register your certificate and receive a Key before you can make use of MapView elements in your application. To make it easier for you to get started using MapView elements, you are welcome to register the debug certificate generated by the SDK tools and receive a temporary Maps API Key. The details of how to do that are given below.

    - -

    When you are preparing to release your application, however, note that you must sign your application with a suitable cryptographic key, rather than the SDK debug key. That means that you will also need to register your application's release certificate with the Google Maps service. After you've done so, you will receive a new Maps API Key that is uniquely associated with your release certificate. To enable the MapView elements in your application to work after release, you must remember to change the Maps API Key for all MapViews in your application so that they refer to the Key associated with your release certificate (rather than your debug certificate).

    - -

    To summarize, the important points to understand about MapViews and the Maps API Key are:

    - -
      -
    • To display Maps data in a MapView, you need to register for a Maps API Key
    • -
    • Each Maps API Key is uniquely associated with a specific certificate, based on an MD5 fingerprint of the certificate
    • -
    • Each MapView must reference a Maps API Key, and the Key referenced must be registered to the certificate used to sign the application
    • -
    • All MapView elements in an application can reference the same Maps API Key
    • -
    • You can register multiple certificates under your developer identity
    • -
    • You can get a temporary Maps API Key based on your debug certificate, but before you publish your application, you must register for a new Key based on your release certificate and update references in your MapViews accordingly
    • -
    - -

    Getting the MD5 Fingerprint of Your Signing Certificate

    - - - -

    To register for a Maps API Key, you need to provide an MD5 fingerprint of the certificate that you will use to sign your application.

    - -

    Before you visit the registration page, use Keytool to generate the fingerprint of the appropriate certificate. - -

    First, determine which key you will use to sign your application at release and make sure of the path to the keystore that contains it.

    - -

    Next, run Keytool with the -list option, against the target keystore and key alias. The table below lists the options you should use.

    - - - - - - - - - - - - - - - - - - - - - -
    Keytool OptionDescription
    -listPrint an MD5 fingerprint of a certificate.
    -keystore <keystore-name>.keystoreThe name of the keystore containing the target key.
    -storepass <password>

    A password for the -keystore.

    As a security precaution, do not include this option -in your command line unless you are working at a secure computer. -If not supplied, Keytool prompts you to enter the password. In this -way, your password is not stored in your shell history.

    -alias <alias_name>The alias for the key for which to generate the MD5 certificate fingerprint.
    -keypass <password>

    The password for the key.

    -

    As a security precaution, do not include this option -in your command line unless you are working at a secure computer. -If not supplied, Keytool prompts you to enter the password. In this -way, your password is not stored in your shell history.

    - -

    Here's an example of a Keytool command that generates an MD5 certificate fingerprint for the key alias_name in the keystore my-release-key.keystore:

    - -
    $ keytool -list -alias alias_name -keystore my-release-key.keystore
    - -

    Keytool will prompt you to enter passwords for the keystore and key. As output of the command, Keytool prints the fingerprint to the shell. For example:

    - -
    Certificate fingerprint (MD5): 94:1E:43:49:87:73:BB:E6:A6:88:D7:20:F1:8E:B5:98
    - -

    Note that, if you happen to forget your Maps API Key, you can repeat the process described above and register the fingerprint again. The server will give you the same key for the specified certificate fingerprint.

    - -

    Once you have the fingerprint, you can go to the Maps API registration site, described next.

    - -

    Getting the MD5 Fingerprint of the SDK Debug Certificate

    - -

    While you are developing and debugging your application, you will likely be -sigining your application in debug mode — that is, the SDK build tools -will automatically sign your application using the debug certificate. To let -your MapView elements properly display Maps data during this period, you should -obtain a temporary Maps API Key registered to the debug certificate. To do so, -you first need to get the MD5 fingerprint of the debug certificate. When -you are ready to release your application, you must register your release -certificate with the Google Maps service and obtain a new Maps API Key. You must -then change the MapView elements in your application to reference the new API -key.

    - -

    To generate an MD5 fingerprint of the debug certificate, first locate the debug keystore. The location at which the SDK tools create the default debug keystore varies by platform:

    - -
      -
    • Windows Vista: C:\Users\<user>\AppData\Local\Android\debug.keystore
    • -
    • Windows XP: C:\Documents and Settings\<user>\Local Settings\Application Data\Android\debug.keystore
    • -
    • OS X and Linux: ~/.android/debug.keystore
    • -
    - -

    If you are using Eclipse/ADT and are unsure where the debug keystore is located, you can select Windows > Prefs > Android > Build to check the full path, which you can then paste into a file explorer to locate the directory containing the keystore.

    - -

    Once you have located the keystore, use this Keytool command to get the MD5 fingerprint of the debug certificate:

    - -
    $ keytool -list -alias androiddebugkey \
    --keystore <path_to_debug_keystore>.keystore \
    --storepass android -keypass android
    - -

    Registering the Certificate Fingerprint with the Google Maps Service

    - -

    When you are ready to register for a Maps API Key, load this page in a browser:

    - -

    http://code.google.com/android/maps-api-signup.html

    - -

    To register for a Maps API Key, follow these steps:

    - -
      -
    1. If you don't have a Google account, use the link on the page to set one up.
    2. -
    3. Read the Android Maps API Terms of Service carefully. If you agree to the terms, indicate so using the checkbox on the screen.
    4. -
    5. Paste the MD5 certificate fingerprint of the certificate that you are registering into the appropriate form field.
    6. -
    7. Click "Generate API Key"
    8. -
    - -

    The server will handle your request, associating the fingerprint with your developer identity and generating a unique Maps API Key, then returning a results page that gives you your Key string.

    - -

    To use the Maps API Key string, copy and paste it into your code as described in the next section.

    - -

    Adding the Maps API Key to your Application

    - -

    Once you've registered with the Google Maps service and have obtained a Maps API Key, you must add it to your application's MapView objects, so that the Maps server will allow them to download Maps tiles.

    - -

    For <MapView> elements declared in XML layout files, add the Maps API Key as the value of a special attribute — android:apiKey. For example: - -

    <com.google.android.maps.MapView
    - android:layout_width="fill_parent"
    - android:layout_height="fill_parent"
    - android:enabled="true"
    - android:clickable="true"
    - android:apiKey="example_Maps_ApiKey_String"
    - />
    - - -

    For MapView objects instantiated directly from code, pass the Maps API Key string as a parameter in the constructor. For example:

    - -
    mMapView = new MapView(this, "example_Maps_ApiKey_String");
    - -

    For more information about MapView, see the MapView class Documentation.

    - -

    Final Steps to Enable MapView Elements

    - -

    If you've added the Maps API Key to the MapViews in your application, here are the final steps to enable the MapView elements to run properly:

    - -
      -
    • Make sure that you added a <uses-library> element referencing the external com.google.android.maps library. The element must be a child of the <application> element in the application's manifest. For example: - -

      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      - package="com.example.package.name">
      - ...
      - <application android:name="MyApplication" >
      -   <uses-library android:name="com.google.android.maps" />
      - ...
      - </application>

    • - -
    • Sign your application with the certificate that corresponds to the Maps API Key referenced in your MapView elements.
    • - -
    - -

    Note that, when you are ready to publish your application, you must get a Maps API Key that is based on the certificate that you will use to sign the application for release. You must then change the Maps API Key string referenced by all of your MapView elements, so that they reference the new Key.

    - - - diff --git a/docs/html/guide/topics/location/index.jd b/docs/html/guide/topics/location/index.jd index 53f1d290ba6489b0b9ded66dc49e35dd3c904ba4..e988ecbc454e7b190a5629ce21b3930019403b69 100644 --- a/docs/html/guide/topics/location/index.jd +++ b/docs/html/guide/topics/location/index.jd @@ -1,35 +1,43 @@ -page.title=Location +page.title=Location and Maps @jd:body
    +

    Location and Maps quickview

    +
      +
    • Android provides a location framework that your application can use to determine the device's location and bearing and register for updates.
    • +
    • A Google Maps external library is available that lets you display and manage Maps data.
    • +

    In this document

      -
    1. android.location
    2. -
    3. com.google.android.maps
    4. +
    5. Location Services
    6. +
    7. Google Maps External Library
    8. +
    +

    See Also

    +
      +
    1. Google APIs add-on download»
    -

    The Android SDK includes two packages that provide Android's primary support -for building location-based services: -{@link android.location} and {@link-fixme com.google.android.maps}. -Please read on below for a brief introduction to each package.

    +

    Location- and maps-based applications and services are compelling for mobile device users. You can build these capabilities into your applications using the classes of the {@link android.location} package and the Google Maps external library. The sections below provide details.

    + +

    Location Services

    -

    android.location

    +

    Android gives your applications access to the location services supported by +the device through the classes in the android.location package. The +central component of the location framework is the +{@link android.location.LocationManager} system service, which provides an API to +determine location and bearing if the underlying device (if it supports location +capabilities).

    -

    This package contains several classes related to -location services in the Android platform. Most importantly, it introduces the -{@link android.location.LocationManager} -service, which provides an API to determine location and bearing if the -underlying device (if it supports the service). The LocationManager -should not be -instantiated directly; rather, a handle to it should be retrieved via -{@link android.content.Context#getSystemService(String) -getSystemService(Context.LOCATION_SERVICE)}.

    +

    As with other system services, you do not instantiate a LocationManager directly. +Rather, you request an LocationManager instance from the system by calling +{@link android.content.Context#getSystemService(String) getSystemService(Context.LOCATION_SERVICE)}. +The method returns a handle to a new LocationManager instance.

    -

    Once your application has a handle to the LocationManager, your application +

    Once your application has a handle to a LocationManager instance, your application will be able to do three things:

      @@ -42,20 +50,20 @@ will be able to do three things:

      lat/long.
    -

    However, during initial development, you may not have access to real -data from a real location provider (Network or GPS). So it may be necessary to -spoof some data for your application, with some mock location data.

    +

    However, during initial development in the emulator, you may not have access to real +data from a real location provider (Network or GPS). In that case, it may be necessary to +spoof some data for your application using a mock location provider.

    Note: If you've used mock LocationProviders in -previous versions of the SDK (m3/m5), you can no longer provide canned LocationProviders +previous versions of the SDK, you can no longer provide canned LocationProviders in the /system/etc/location directory. These directories will be wiped during boot-up. -Please follow the new procedures below.

    - +Please follow the new procedures outlined below.

    Providing Mock Location Data

    When testing your application on the Android emulator, there are a couple different -ways to send it some spoof location data: with the DDMS tool or the "geo" command.

    +ways to send it some mock location data: you can use the DDMS tool or the "geo" command +option in the emulator console.

    Using DDMS

    With the DDMS tool, you can simulate location data a few different ways:

    @@ -67,9 +75,9 @@ ways to send it some spoof location data: with the DDMS tool or the "geo" comman

    For more information on using DDMS to spoof location data, see the Using DDMS guide. -

    Using the "geo" command

    +

    Using the "geo" command in the emulator console

    Launch your application in the Android emulator and open a terminal/console in -your SDK's /tools directory. Now you can use:

    +your SDK's /tools directory. Connect to the emulator console. Now you can use:

    • geo fix to send a fixed geo-location.

      This command accepts a longitude and latitude in decimal degrees, and an optional altitude in meters. For example:

      @@ -82,28 +90,51 @@ your SDK's /tools directory. Now you can use:

    - -

    com.google.android.maps

    - -

    This package introduces a number of classes related to -rendering, controlling, and overlaying customized information on your own -Google Mapified Activity. The most important of which is the -{@link-fixme com.google.android.maps.MapView} class, which automagically draws you a -basic Google Map when you add a MapView to your layout. Note that, if you -want to do so, then your Activity that handles the -MapView must extend {@link-fixme com.google.android.maps.MapActivity}.

    - -

    Also note that you must obtain a MapView API Key from the Google Maps -service, before your MapView can load maps data. For more information, see -Obtaining a MapView API Key.

    - -

    Once you've created a MapView, you'll probably want to use -{@link-fixme com.google.android.maps.MapView#getController()} to -retrieve a {@link-fixme com.google.android.maps.MapController}, for controlling and -animating the map, and {@link-fixme com.google.android.maps.ItemizedOverlay} to -draw {@link-fixme com.google.android.maps.Overlay}s and other information on the Map.

    - -

    This is not a standard package in the Android library. In order to use it, you must add the following node to your Android Manifest file, as a child of the -<application> element:

    -
    <uses-library android:name="com.google.android.maps" />
    +

    For information about how to connect to the emulator console, see +Using the Emulator Console.

    + +

    Google Maps External Library

    + +

    To make it easier for you to add powerful mapping capabilities to your +application, Google provides a Maps external library that includes the +com.google.android.maps package. The classes of the com.google.android.maps +package offer built-in downloading, rendering, and caching of Maps tiles, as +well as a variety of display options and controls.

    + +

    The key class in the Maps package is +com.google.android.maps.MapView, a subclass of +{@link android.view.ViewGroup ViewGroup}. A MapView displays a map with data obtained +from the Google Maps service. When the MapView has focus, it will capture +keypresses and touch gestures to pan and zoom the map automatically, including +handling network requests for additional maps tiles. It also provides all of the +UI elements necessary for users to control the map. Your application can also +use MapView class methods to control the MapView programmatically and draw a +number of Overlay types on top of the map.

    + +

    In general, the MapView class provides a wrapper around the Google Maps API +that lets your application manipulate Google Maps data through class methods, +and it lets you work with Maps data as you would other types of Views.

    + +

    The Maps external library is not part of the standard Android library, so it +may not be present on some compliant Android-powered devices. Similarly, the +Maps external library is not included in the standard Android library provided +in the SDK. So that you can develop using the classes of the +com.google.android.maps package, the Maps external library is made available to +you as part of the Google APIs add-on for the Android SDK.

    + +

    To learn more about the Maps external library and how to download and use the +Google APIs add-on, visit

    + +

    http://code.google.com/android/add-ons/google-apis

    + +

    For your convenience, the Google APIs add-on is also included in the Android +SDK.

    + +

    Note: In order to display Google Maps data in a +MapView, you must register with the Google Maps service and obtain a Maps API +Key. For information about how to get a Maps API Key, see Obtaining +a Maps API Key.

    diff --git a/docs/html/guide/topics/media/index.jd b/docs/html/guide/topics/media/index.jd index 4541024111b9e61aa83028a7045cdeae7bb43b2a..96c500cab7c80713d5182accd507461495016962 100644 --- a/docs/html/guide/topics/media/index.jd +++ b/docs/html/guide/topics/media/index.jd @@ -9,24 +9,33 @@ page.title=Audio and Video
  • Audio playback and record
  • Video playback
  • Handles data from raw resources, files, streams
  • -
  • Built-in codecs for a variety of media. See Android 1.0 Media Formats
  • +
  • Built-in codecs for a variety of media. See Android Supported Media Formats
  • Key classes

      -
    1. MediaPlayer (all audio and video formats)
    2. -
    3. MediaRecorder (record, all audio formats)
    4. +
    5. {@link android.media.MediaPlayer MediaPlayer} (all available formats)
    6. +
    7. {@link android.media.MediaRecorder MediaRecorder} (all available formats)
    8. +
    9. {@link android.media.JetPlayer JetPlayer} (playback, JET content)
    10. +
    11. {@link android.media.SoundPool SoundPool} (sound management)

    In this document

      -
    1. Audio and Video Playback
    2. +
    3. Audio and Video Playback +
        +
      1. Playing from a Raw Resource
      2. +
      3. Playing from a File or Stream
      4. +
      5. Playing JET Content
      6. +
      +
    4. Audio Capture

    See also

    1. Data Storage
    2. +
    3. JetCreator User Manual
    @@ -115,6 +124,28 @@ above.

    If you're passing a URL to an online media file, the file must be capable of progressive download.

    +

    Playing JET content

    +

    The Android platform includes a JET engine that lets you add interactive playback of JET audio content in your applications. You can create JET content for interactive playback using the JetCreator authoring application that ships with the SDK. To play and manage JET content from your application, use the {@link android.media.JetPlayer JetPlayer} class.

    + +

    For a description of JET concepts and instructions on how to use the JetCreator authoring tool, see the JetCreator User Manual. The tool is available fully-featured on the OS X and Windows platforms and the Linux version supports all the content creation features, but not the auditioning of the imported assets.

    + +

    Here's an example of how to set up JET playback from a .jet file stored on the SD card:

    + +
    +JetPlayer myJet = JetPlayer.getJetPlayer();
    +myJet.loadJetFile("/sdcard/level1.jet");
    +byte segmentId = 0;
    +
    +// queue segment 5, repeat once, use General MIDI, transpose by -1 octave
    +myJet.queueJetSegment(5, -1, 1, -1, 0, segmentId++);
    +// queue segment 2
    +myJet.queueJetSegment(2, -1, 0, 0, 0, segmentId++);
    +
    +myJet.play();
    +
    + +

    The SDK includes an example application — JetBoy — that shows how to use {@link android.media.JetPlayer JetPlayer} to create an interactive music soundtrack in your game. It also illustrates how to use JET events to synchronize music and game logic. The application is located at <sdk>/platforms/android-1.5/samples/JetBoy. +

    Audio Capture

    Audio capture from the device is a bit more complicated than audio/video playback, but still fairly simple:

      diff --git a/docs/html/guide/topics/media/jet/jetcreator_manual.jd b/docs/html/guide/topics/media/jet/jetcreator_manual.jd new file mode 100644 index 0000000000000000000000000000000000000000..9692d9767815bcbfd2685b536202cec8e1165559 --- /dev/null +++ b/docs/html/guide/topics/media/jet/jetcreator_manual.jd @@ -0,0 +1,1152 @@ +page.title=SONiVOX JETCreator User Manual +@jd:body + + + +

      Content Authoring Application for the JET Interactive Music Engine

      + + +

      1 Introduction

      + +

      1.1 Overview

      + +

      This document contains the user guidelines +for the SONiVOX JET Creator, an authoring application for creating and +auditioning JET files. JET is an interactive music player for small embedded +devices, including the those running the Android platform. It allows applications to +include interactive music soundtracks, in MIDI +format, that respond in real-time to game play events and user interaction.

      + + +

      JET works in conjunction with SONiVOX's +Embedded Audio Synthesizer (EAS) which is the MIDI +playback device for Android. Both the +JET and EAS engines are integrated into the Android embedded platform through the +{@link android.media.JetPlayer} class, as well +as inherent in the JET Creator application. As such, the JET content author can +be sure that the playback will sound exactly the same in both the JET Creator +and the final Android application playing back on Android mobile devices.

      + + +

      In addition to the graphical user +interface, there are two main functionalities taking place in JET Creator. The +first involves gathering all the source data (MIDI +files and DLS file), adding JET's real-time attributes and building a JET +(.jet) file that the Android application will use. The second functionality +involves auditioning the interactive playback elements as they will take place +in the Android application.

      + + +

      The JET Creator application is written in +the Python programming language, therefore you need to have the current version +of Python and WXWidgets installed. There is both a Mac and Windows version.

      + + +

      1.2 Abbreviations and Common Terms

      + +

      It is important to use a common set of +terms to minimize confusion. Since JET uses MIDI +in a unique way, normal industry terms may not always suffice. Here is the +definition of terms as they are used in this document and in the JET Creator +application:

      + + +

      Channel: MIDI data associated with a specific MIDI +channel. Standard MIDI allows for 16 channels of MIDI +data each of which are typically associated with a specific instrument.

      + + + +

      Controller: A MIDI event consisting of a +channel number, controller number, and a controller value. The MIDI + spec associates many controller numbers with +specific functions, such as volume, expression, sustain pedal, etc. JET also +uses controller events as a means of embedding special control information in a +MIDI sequence to provide for audio synchronization.

      + + + +

      DAW: Digital Audio Workstation. A common term for MIDI +and audio sequencing applications such as Logic, SONAR, Cubase and others.

      + + + +

      EAS: Embedded MIDI Synthesizer. The +name of the SONiVOX MIDI synthesizer engine.

      + + + +

      JET: Jet Interactive Engine. The name of the SONiVOX JET interactive +music engine.

      + + + +

      M/B/T: Measures, Beats and Ticks

      + + + +

      Segment: A musical section such as a chorus or verse that is a component of +the overall composition. In JET, a segment can be an entire MIDI file or a +derived from a portion of a MIDI file.

      + + + +

      SMF-0: Standard MIDI File Type 0, a MIDI file that contains a single +track, but may be made up of multiple channels of MIDI +data.

      + + + +

      SMF-1: Standard MIDI File Type 1, a MIDI file that contains a one more +tracks, and each track may in turn be made up of one or more channels of MIDI + data. By convention, each channel is stored on a +separate track in an SMF-1 file. However, it is possible to have multiple MIDI +channels on a single track, or multiple tracks that contain data for the same MIDI +channel.

      + + + +

      Track: A single track in a DAW containing a timed sequence of events. Be careful not to confuse Tracks with +Channels. A MIDI file may contain many tracks with several tracks utilizing the +same MIDI channel.

      + + + + + +

      2 The JET Interactive Music Concept

      + +

      Interactive music can be defined as music +that changes in real-time according to non-predictable events such as user +interaction or game play events. In this way, interactive music is much more +engaging as it has the ability to match the energy and mood of a game much +closer than a pre-composed composition that never changes. In some applications +and games, interactive music is central to the game play. Guitar Hero is one +such popular game. When the end user successfully captures the musical notes +coming down the fret board, the music adapts itself and simultaneously keeps +score of successes and failures. JET allows for these types of music driven +games as well.

      + + + +

      There are several methods for making and +controlling interactive music and JET is one such method. This section +describes the features of JET and how they might be used in a game or software +application. It also describes how JET can be used to save memory in small +footprint devices such as Android enabled mobile handsets.

      + +

      2.1.1 Data Compression

      + +

      JET supports a flexible music format that +can be used to create extended musical sequences with a minimal amount of data. +A musical composition is broken up into segments that can be sequenced to +create a longer piece. The sequencing can be fixed at the time the music file +is authored, or it can be created dynamically under program control.

      + +

      2.1.2 Linear Music Example

      + +

      + +
      Figure 1: Linear Music Piece

      + +

      This diagram shows how musical segments are +stored. Each segment is authored as a separate MIDI +file. A post-processing tool combines the files into a single container file. +Each segment can contain alternate music tracks that can be muted or un-muted +to create additional interest. An example might be a brass accent in the chorus +that is played only the last time through. Also, segments can be transposed up +or down.

      + + +

      The bottom part of the diagram shows how +the musical segments can be recombined to create a linear music piece. In this +example, the bridge might end with a half-step key modulation and the remaining +segments could be transposed up a half-step to match.

      + +

      2.1.3 Non-linear Music Example

      + +

      + +
      Figure 2: Non-linear music piece

      + + +

      In this diagram, we see a non-linear music +piece. The scenario is a first-person-shooter (FPS) and JET is providing the +background music. The intro plays as the level is loading and then transitions +under program control to the Searching segment. This segment is repeated indefinitely, +perhaps with small variations (using the mute/un-mute feature) until activity +in the game dictates a change.

      + + + +

      As the player nears a monster lair, the +program starts a synchronized transition to the Danger segment, increasing the +tension level in the audio. As the player draws closer to the lair, additional +tracks are un-muted to increase the tension.

      + + + +

      As the player enters into combat with the +monster, the program starts a synchronized transition to the Combat segment. +The segment repeats indefinitely as the combat continues. A Bonus Hit +temporarily un-mutes a decorative track that notifies the player of a +successful attack, and similarly, another track is temporarily un-muted to +signify when the player receives Special Damage.

      + + + +

      At the end of combat, the music transitions +to a victory or defeat segment based on the outcome of battle.

      + +

      2.1.4 Mute/Un-mute Synchronization

      + +

      JET can also synchronize the muting and +un-muting of tracks to events in the music. For example, in the FPS game, it would +probably be desirable to place the musical events relating to bonuses and +damage as close to the actual game event as possible. However, simply un-muting +a track at the moment the game event occurs might result in a music clip +starting in the middle. Alternatively, a clip could be started from the +beginning, but then it wouldn't be synchronized with the other music tracks.

      + + +

      However, with the JET sync engine, a clip +can be started at the next opportune moment and maintain synchronization. This +can be accomplished by placing a number of short music clips on a decorative +track. A MIDI event in the stream signifies +the start of a clip and a second event signifies the end of a clip. When the +application calls the JET clip function, the next clip in the track is allowed +to play fully synchronized to the music. Optionally, the track can be +automatically muted by a second MIDI event.

      + + +

      + +
      Figure 3: Synchronized Mute/Unmute

      + + +

      2.2 Audio Synchronization

      + +

      JET provides an audio synchronization API +that allows game play to be synchronized to events in the audio. The mechanism +relies on data embedded in the MIDI file at +the time the content is authored. When the JET engine senses an event during +playback it generates a callback into the application program. The timing of +the callback can be adjusted to compensate for any latency in the audio +playback system so that audio and video can be synchronized. The diagram below +shows an example of a simple music game that involves pressing the left and +right arrows in time with the music.

      + +

      +
      Figure 4: Music Game

      + + + +

      The arrows represent events in the music sequence +where game events need to be synchronized. In this case, the blue arrow +represents a time where the player is supposed to press the left button, and +the red arrow is for the right button. The yellow arrow tells the game engine +that the sequence is complete. The player is allowed a certain time window +before and after the event to press the appropriate key.

      + + + +

      If an event is received and the player has +not pressed a button, a timer is set to half the length of the window. If the +player presses the button before the timer expires, the game registers a +success, and if not, the game registers a failure.

      + + + +

      If the player presses the button before the +event is received, a timer is set to half the length of the window. If an event +is received before the timer expires, the game registers a success, and if not, +the game registers a failure. Game play might also include bonuses for getting +close to the timing of the actual event.

      + + + +

      3 JET Content Authoring Overview

      + +

      To author JET files and hear them playback +interactively, the content author will work in two applications which are +designed to work together smoothly. The first is application is any +off-the-shelf MIDI sequencing application that +supports VST (for PC) or AU (for Mac) plugins. Here the author will compose +their MIDI music files using the plugin as the +synthesizer device. The second application is the JET Creator application. Here +the author will import their MIDI music files +(and optionally a DLS2 soundset) and setup the conditions for interactive +playback within the JET enabled game. Optionally the content author may create +a custom set of DLS instruments using an instrument editor that supports the +DLS Level 2 format. One such application is Awave from MJSoft.

      + +

      Please see the JET Content Authoring Guidelines documentation for additional +details on content authoring.

      + + + +

      4 Installing and Launching JET Creator

      + +

      JET Creator is a python language +application, therefore, you must have Python and wxPython installed on your +machine.

      + + +

      JetCreator was created and tested with:

      + +

      Python Version 2.5.4

      + +

      wxPython Version 2.8.7.1

      + + +

      These can be downloaded here:

      + + + +

      PC:

      +
        +
      • http://www.python.org/download/releases/2.5.4/
      • + +
      • http://www.wxpython.org/download.php
      • +
      + + +

      MAC:

      +
        +
      • http://wiki.python.org/moin/MacPython/Leopard
      • + +
      • http://www.wxpython.org/download.php
      • +
      + + +

      After installing Python and wxPython, +simply unzip or copy all the files in the JET Creator application directory to +a folder on your hard drive.

      + + +

      To launch JET Creator go to a command +prompt and set the directory to where you've installed Python. Next run python +with the command:

      + +

      python jetcreator.py

      + + + + + +

      5 Using JET Creator

      + + + +

      5.1 File Types

      + +

      There are a few different file types +associated with JET Creator.

      + + + +

      .jtc JET +Creator project file. This file contains all the information associated with a +JET Creator project. When you Save or Save-as out of JET Creator, this file +type is saved.

      + + + +

      .jet JET +File. This output file is automatically generated from JET Creator whenever you +save your JET Creator project. This is the file that bundles all JET assets +together into a single file that the Android application will use. Give this +file to the Android application developer.

      + + + +

      .mid File. This is the standard MIDI +type 1 file that JET Creator will use to make segments.

      + + + +

      .seg Segment +File. This is a JET Segment file. It has the same name as the MIDI +file which it references but contains additional Segment information.

      + + + +

      .zip Zip +Archive file. When you Export a JET Archive, a zip file is created that +contains all the assets (files) necessary for JET Creator. Use this to transfer +JET Creator projects to other people.

      + + + +

      5.2 Open Dialog

      + +

      When +you first launch JET Creator you are presented with an open dialog like the +following.

      + + + +

      + + + + + +

      Open will open an existing .jtc (JET Creator file) file. Use the browser +button to browse to the directory where you have saved your .jtc file.

      + + + +

      New will create a new .jtc file.

      + + + +

      Import will import a JET Archive (.zip) file.

      + + + +

      Cancel will cancel the dialog and exit the application.

      + + + + + +

      5 Main Window

      + +

      The main window of the JET Creator +application looks like the picture below. There are three main sections from +top to bottom: segment view, event view, and timeline.

      + + + +

      The segment view section displays a list of +the current segments, which MIDI file and +(optionally) DLS2 file each segment is derived from. It also shows each +segments start and stop time and each segments quantize, transpose, repeat and +mute flag settings.

      + + + +

      Just below the Segment view is the event +view. The event view section displays all events associated with a given +segment. Events only display when the segment they are assigned to is +highlighted. Each event displays its type, start and end points, track and midi +channel assignment, and its event ID.

      + + + +

      Just below the Event view is the timeline +display. The timeline shows how many measures a given segment is as well as any +events associated with that segment. The timeline changes to display the +currently selected or playing segment. You can trigger an event in this window +while the segment is play by simply clicking on the event in the timeline +display.

      + + +

      +
      JET +Creator Main Window

      + + +

      The buttons along the left side of main +window do the following:

      + +

      Add: +Displays the segment or event window for adding a new segment or event

      + +

      Revise: +Displays the segment or event window for updating an existing segment or event

      + +

      Delete: +Deletes the selected segment or event (will ask for confirmation)

      + +

      Move: +Displays the move window which allows you to move selected segments or events +in time

      + +

      Queue All: Queue's +(selects) all segments for playback

      + +

      Dequeue All: Dequeues +(deselects) all segments

      + +

      Play: +Starts playback of all queued segments. This button changes to Stop if any +segments are playing

      + +

      Audition: +Displays the Audition window (see below)

      + + + +

      5.1 Segment Window

      + +

      The segment window is where a given +segment's attributes are assigned and auditioned, as shown in the picture +below. The left side of the window displays the segments attributes that are +stored in the JET file. The right side of the window allows the author to set +mute flags, repeat and transpose settings and audition the segment as it will +play in the JET game.

      + + + +

      Note: the audition attributes (mute flags, repeat and transpose) are not stored in the JET content file +(.jet) but rather are defined by the game or application itself. In programming +language, these settings correspond directly with the API calls to the JET +engine. By including them here, the JET content author can simulate how the +segment will respond to the applications API commands during game play.

      + + + +

      +

      + +

      The segment parameters do the following:

      + +
        +
      • Segment Name - Sets +the name of the segment
      • + +
      • MIDI File - +The name and location of the MIDI file from which +the segment is derived. The button to the immediate right will bring up a +browser for locating a midi file on the hard drive.
      • + +
      • DLS File - +The name and location of the DLS2 file, if any, that the MIDI +file uses for that segment.
      • + +
      • Starting M/B/T - +Starting measure, beat and tick of the segment
      • + +
      • Ending M/B/T - +Ending measure, beat and tick of the segment
      • + +
      • Quantize - +Quantize value for quantizing the current segment during playback
      • + +
      + +

      The audition fields are as follows:

      + +
        +
      • Track Mutes - +Shows the MIDI tracks (not channels) +in the MIDI file. Clicking on a track's +checkbox will mute that track.
      • + +
      • Channel - +Displays the MIDI channel assigned to each +track
      • + +
      • Name - +Displays the track name meta event (if present) for each track
      • + +
      • Repeat - +Indicates the number of times a segment should repeat during playback
      • + +
      • Transpose - +Indicates the transposition in semi-tones or half-steps a segment should +transpose during playback
      • + +
      • To the right of the Audition window are a few additional buttons. +These do as follows:
      • + +
      • OK - +Selecting OK confirms all segment settings and closes the segment window
      • + +
      • Cancel - +Selecting Cancel cancels any changes and closes the segment window
      • + +
      • Replicate - +Displays the Replicate Segment window for entering multiple segments at once. +See below.
      • + +
      • Play/Stop Segment - Starts +or Stops playback of the segment using the segment attributes assigned.
      • + +
      • Play/Stop MIDI File - +Starts or Stops playback of the MIDI file +which the segment is assigned to.
      • + +
      • Pause/Resume - +Pauses or Resumes playback.
      • + +
      + + + +

      5.2 Event Window

      + +

      The event window is where a given segment's +event attributes are assigned and auditioned, as shown in the picture below. To +add an event to a segment, the author must first select the segment which will +contain the event, then select the Add button. This will bring up the Event +window.

      + + + +

      +

      + + + + + +

      There are two main sections to the event +window. The segment section on the left side of the event window is for display +only. It shows what the segment attributes are for the given segment. The Event +section, on the right side, is where events can be assigned. The following +parameters are available:

      + + + +

      Event Name - +Assigns a name to an event

      + +

      Event Type - +Selects which type of event to assign.

      + +

      Starting M/B/T - +Sets the starting measure, beat, and tick for the event

      + +

      Ending M/B/T - +Sets the ending measure, beat, and tick for the event, if applicable

      + +

      Track - +Sets which track in the given segment the event will apply to

      + +

      Channel - +Sets which MIDI channel the event will apply +to. The MIDI channel should match the MIDI +channel of the track

      + +

      Event ID - +Sets the event ID for the event. Multiple events can be assigned to the same +segment and therefore the Event ID is used to identify them

      + + + +

      To the right of the Audition window are a few additional buttons. +These do as follows:

      + +

      + +

      OK - +Selecting OK confirms all event settings and closes the event window

      + +

      Cancel - +Selecting Cancel cancels any changes and closes the event window

      + +

      Replicate - +Displays the Replicate Event window for entering multiple events at once. See +below.

      + +

      Play/Stop - +Starts or Stops playback of the segment using the segment attributes assigned. +While the segment is playing, events can be triggered and auditioned.

      + +

      Trigger - +Triggers the event assigned. This replicates the API command that the JET game +will use to trigger the event, therefore giving the content author a method for +auditioning the behaviour of the event.

      + +

      Mute/UnMute - +Mute/UnMute will mute or unmute the track that the event is assigned to

      + +

      Pause/Resume - +Pauses or Resumes playback.

      + + + +

      To audition the behaviour of an event, you +can select the Play button. This will initiate playback. The trigger button +will send the trigger event when pressed. This is equivalent to selecting the +green trigger event in the timeline.

      + + + +

      Note: Trigger events are meant to unmute a +single track of a segment when triggered, then mute that track at the end of +the trigger segment. Therefore you should make sure the mute flag is set to +mute the track that a trigger event will be unmuting when receiving a trigger event. +

      + + + +

      Please read Section 6 Under The Hood +below for details on how trigger events work and behave.

      + + + +

      5.3 Replicate Windows

      + +

      Often in creating JET files, you'll need to +create tens or even hundreds of events. You may also need to move events. The +Replicate and Move windows allow for this. There are two Replicate windows for +creating multiple segments or events. They look like the following:

      + + + +

      + +

      Replicate Segment Window

      + + +

      + + + +

      Replicate Event Window

      + + + +

      Both Replicate windows function the same. +After creating an initial segment or event, you can select the Replicate +button. The parameters are as follows:

      + + + +

      Name Prefix - +Sets the prefix for the name of each segment or event created

      + +

      Starting M/B/T - +Sets the starting time for the first segment or event

      + +

      Increment M/B/T - +Sets the time between segments or events created.

      + +

      Number - +Sets the number of segments or events you wish to create. If the number +overflows the length of the MIDI file (for +segments) or segment (for events), those objects will not be created.

      + +

      Preview - +Preview allows you to examine the objects created before saying OK to insert +them.

      + + + + + +

      5.4 Move Windows

      + +

      The Move function acts similarly to the +Replicate function in that it allows you to edit multiple segments or events at +one time, in this case move them in time. Like Replicate, there are two Move +windows, one for Segments and one for Events. The windows look like the +following:

      + + + +

      + + + +

      Move Event Window

      + + + +

      To use Move, first select the segments or +events you wish to move in time, then click the Move button. The parameters are +as follows:

      + + + +

      Starting M/B/T - +Sets the starting time for the first segment or event

      + +

      Increment M/B/T - +Sets the time in M/B/T you wish to move the objects by.

      + +

      Preview - +Preview allows you to examine the objects created before saying OK to move +them.

      + + + + + +

      5.5 Audition Window

      + +

      Clicking the Audition button in the main +window of the JET Creator application will open the Audition window. This is +where the content author or application programmer can simulate the interactive +playback as it may occur in the mobile application or game itself.

      + + + +

      + + + +

      JET Audition Window

      + + + + + +

      There are four main sections to the +audition window. The left most section displays the available segments and +their length in seconds. The middle section displays a running list of what +segments are queued for playback and what their playback status is. The far +right section displays the mute flags for the currently playing segment. The +timeline section at the bottom is the same as in the main window. It displays +the currently playing segment as well as a visual display of any event triggers +associated with that segment.

      + + + +

      The Audition window allows you to queue up +any segment in any order for playback. To do this simply select the segment you +wish to cue and hit Queue. That segment will appear in the queue window and +start playing (if it is the first segment). Subsequently you can select any +other segment or segments and cue them up for playback. As the segments +complete playback, the next segment in the queue will begin playing. As is the +other windows of JET Creator, you can mute, unmute, trigger event clips, etc. +in realtime as each segment is playing back.

      + + + +

      Specifically the buttons behave as follows:

      + + + +

      Queue - +loads the selected segment into the queue and starts playback

      + +

      Cancel and Queue - +cancels the currently playing segment before queueing the selected segment for +playback

      + +

      Cancel Current - +cancels the currently playing segment in the queue and begins playback of the +next segment

      + +

      Stop - +stops playback of all queued segments

      + +

      Mute All - +mutes all tracks in the current segment

      + +

      Mute None - +unmutes all tracks in the current segment

      + +

      Original Mutes - +sets the original mute flags for the current segment

      + + + +

      The combination of these playback options +allows an author or application programmer to audition any behaviour an +interactive music application may encounter.

      + + + + + +

      5.6 JET Creator Menus

      + +

      The JET Creator menus provide access to +many of the parameters in the main window plus a few additional parameters.

      + +

      5.6.1 File Menu

      + +

      The File Menu contains the following +elements:

      + + + +

      New - +Creates a new JET Creator file (.jtc)

      + +

      Open - +Opens an existing JET Creator file

      + +

      Save - +Saves the currently opened JET Creator file

      + +

      Save As - +Saves the currently opened JET Creator file to a new file

      + +

      Import Project - Imports a JET Creator archive (.zip)

      + +

      Export Project - Exports a JET Creator archive (.zip)

      + +

      Exit - +Exits the application

      + + + +

      5.6.2 Edit Menu

      + +

      The Edit Menu contains the following +elements:

      + + + +

      Undo - +Undo will undo the last edit made

      + +

      Redo - +Redo will redo the last undo

      + +

      Cut - +Copy selected parameter into clipboard and Delete selection

      + +

      Copy - +Copy selected parameter into clipboard and keep selection

      + +

      Paste - +Paste selected parameter

      + + + +

      5.6.3 JET

      + +

      The Edit Menu contains the following +elements:

      + + + +

      Properties - +Brings up the JET Creator priorities window. This window allows you to set the +following conditions for a given JET file:

      + +

      Copyright Info - Contains copyright info to be inserted into JET file

      + +

      Chase Controllers - Option to chase controllers (on/off). This should usually +be ON.

      + +

      Delete Empty Tracks - Deletes any empty MIDI tracks

      + + + +

      5.6.4 Segments

      + +

      The Segments Menu contains the following +elements:

      + + + +

      Add Segment - +Brings up the Segment window

      + +

      Update Segment - Updates segment attributes

      + +

      Delete Segment - Deletes the current segment from the +Segment List

      + + + +

      5.6.5 Help

      + +

      The Help Menu will contain at least the +following elements:

      + + + +

      JET Creator Help - will launch PDF help document or go to on-line help

      + +

      About - +JET Creator version number, SONiVOX info

      + + + + + +

      6 Trigger Events Explained

      + +

      Breaking a MIDI +file into individual (non-linear) segments and queueing up those segments for +playback in a game based on events within the game is one way JET music files are +interactive. Trigger events are an additional method for interactive playback. +Both would be used together in an interactive game or application.

      + + + +

      Trigger events allow for the following:

      + + +
        +
      1. Tracks within a MIDI segment can be turned on or off based on game + events. For example the composer could author two drum tracks, one fast + and one slow. If the action in a game is fast, the fast drum track could + play. If the action in the game is slow, the slow drum track can play.
      2. +
      3. User actions can be compared to trigger events which are + pre-inserted into a music file at musically correct places. Based on the + results, scoring or other game actions can take place.
      4. +
      5. Musical transitions between levels or action sequences can be + synchronized to be musically seemless.
      6. +
      + + + +

      Under the hood, JET uses standard MIDI CC +events to accomplish these actions and to synchronize audio. The controllers +used by JET are among those not defined for specific use by the specification. The specific controller definitions +are as follows:

      + + + +

      Controllers +80-83 Reserved for use by +application

      + +

      Controller +102 JET event marker

      + +

      Controller +103 JET clip marker

      + +

      Controllers +104-119 Reserved for future use

      + + + +

      6.1 JET Clip Marker (CC103)

      + +

      Controller 103 is reserved for marking +clips in a MIDI track that can be triggered by +the JET_TriggerClip API call. The clip ID is encoded in the low 6 bits of the +controller value. Bit 6 is set to one to indicate the start of a clip, and set +to zero to indicate the end of a clip.

      + + + +

      For example, to identify a clip with a clip +ID of 1, the author inserts a MIDI controller +event with controller=103 and value=65 at the start of the clip and another +event with controller=103 and value=1 at the end of the clip. When the +JET_TriggerClip() function is called with a clip ID of 1, the track will be +un-muted when the controller value 65 is encountered and muted again when the +controller value 1 is encountered.

      + + + +

      + +

      Figure 5: Synchronized Clip

      + + + +

      In the figure above, if the +JET_TriggerClip() function is called prior to the first controller event, Track +3 will be un-muted when the first controller event occurs, the first clip will +play, and the track will be muted when the second controller event occurs. If +the JET_TriggerClip() function is called after the first controller event has +occurred, Track 3 will be un-muted when the third controller event occurs, the +second clip will play, and the track will be muted again when the fourth +controller event occurs.

      + + + +

      Note: Normally, the track containing the clip is muted by the application +when the segment is initially queued by the call to JET_QueueSegment(). If it +is not muted, the clip will always play until Jet_TriggerClip() has been called +with the clip ID.

      + + + +

      6.2 JET Event Marker (CC102)

      + +

      Controller 102 is reserved for marking +events in the MIDI streams that are specific +to JET functionality. Currently, the only defined value is 0, which marks the +end of a segment for timing purposes.

      + + + +

      Normally, JET starts playback of the next +segment (or repeats the current segment) when the MIDI +end-of-track meta-event is encountered. Some MIDI +authoring tools make it difficult to place the end-of-track marker accurately, +resulting in synchronization problems when segments are joined together.

      + + + +

      To avoid this problem, the author can place +a JET end-of-segment marker (controller=102, value=0) at the point where the +segment is to be looped. When the end-of-segment marker is encountered, the +next segment will be triggered, or if the current segment is looped, playback +will resume at the start of the segment.

      + + + +

      The end-of-segment marker can also be used +to allow for completion of a musical figure beyond the end of measure that +marks the start of the next segment. For example, the content author might +create a 4-bar segment with a drum fill that ends on beat 1 of the 5th +bar, a bar beyond the natural end of the segment. By placing an end-of-segment +marker at the end of the 4th bar, the next segment will be +triggered, but the drum fill will continue in parallel with the next segment +providing musical continuity.

      + + + +

      + +

      Figure 6: End-of-segment Marker

      + +

      6.3 Application Controllers (CC80-83)

      + +

      The application may use controllers in this +range for its own purposes. When a controller in this range is encountered, the +event is entered into an event queue that can be queried by the application. +Some possible uses include synchronizing video events with audio and marking a +point in a MIDI segment to queue up the next +segment. The range of controllers monitored by the application can be modified +by the application during initialization.

      + +

      7 JET Creator Guidelines

      + +

      + +

      7.1 Order of Tasks

      + +

      As with all projects, its best to discuss and design the interactive music scheme with the game designer and programmer before beginning your composition. An outline and/or specification can go a long way in saving you from having to redo things after the game is in place.

      + +

      In general you’ll want to first write your music in your DAW of choice the way you’re used to composing, then break up the final MIDI file as needed for the application. Next, move to JET Creator and create all of your music segments in the order easiest to preview them when played in order. Finally, add the JET Events to control the segments via the Android game and Audition them as needed in JET Creator. Finally, save the project in JET Creator and hand off the .jet file to the programmer to integrate it in the game. After previewing there will likely be changes to the MIDI file(s) and JET Creator attributes.

      + +

      7.2 Conserving Memory

      + +

      If you’re trying to conserve memory, compose as few MIDI files as possible, and create several segments from that MIDI file. For example a 12 bar MIDI file with three sections of 4 bars, A, B, C, can create a much longer song. Simply create multiple segments that reference the one MIDI file, then order them however you like. For example, A, A, B, A, C, A, B, A, A would create a 36 bar song. Use JET to add repeats, transpose segments, and interactively mute and unmute tracks to keep it even more interesting.

      + +

      7.3 Replicate

      + +

      To make adding segments or events faster, use the Replicate command. Replicate can add multiple segments or events at one time and uses an offset parameter and prefix naming convention to keep things easy to read. The MOVE command is also useful for moving multiple events by a set number of measures, beats or ticks.

      + +

      7.4 Interactive Options

      + +

      There are several interactive audio concepts possible in JET. Below are a few examples although we hope developers will come up with others we haven’t thought of! These are:

      + +

      7.4.1 Multiple Segment Triggering

      + +

      In this method the application is triggering specific segments based on events in the game. For example a hallway with lots of fighting might trigger segment 1 and a hallway with no fighting might trigger segment 2. Using JET TriggerClips in conjunction with this method creates even more diversity.

      + +

      7.4.2 Mute Arrays

      + +

      In this method the application is triggering mute and unmute events to specific tracks in a single MIDI sequence. For example a hallway with lots of fighting might play MIDI tracks 1-16 and a hallway with no fighting might play the same midi file but mute tracks 9-16. Using JET TriggerClips in conjunction with this method creates even more diversity.

      + +

      7.4.3 Music Driven Gameplay

      + +

      Music driven gaming is similar to what Guitar Hero and JETBOY have done in that the music content determines how graphic events are displayed. The application then queries the user response to the graphic events and interactively modifies the music in response. In this method the game is utilizing JET Application Events, MIDI controllers that are embedded in the MIDI file and read by the game in real-time. Based on the user response, multiple segment triggering and/or mute arrays can be set.

      + diff --git a/docs/html/guide/topics/media/media.jd b/docs/html/guide/topics/media/media.jd deleted file mode 100644 index 463686d367aeb96fd69532b5eb19e8b029bacc8b..0000000000000000000000000000000000000000 --- a/docs/html/guide/topics/media/media.jd +++ /dev/null @@ -1,172 +0,0 @@ -page.title=Media Capabilities -@jd:body - - - -

      The Android platform offers built-in encoding/decoding for a variety of common media types, -so that you can easily integrate audio, video, and images into your applications. Accessing the platform's media -capabilities is fairly straightforward &mdash you do so using the same intents and -activities mechanism that the rest of Android uses.

      - -

      Android lets you play audio and video from several types of data sources. You can play audio or video from media files stored in the application's resources (raw resources), from standalone files in the filesystem, or from a data stream arriving over a network connection. To play audio or video from your application, use the {@link android.media.MediaPlayer} class.

      - -

      The platform also lets you record audio, where supported by the mobile device hardware. Recording of video is not currently supported, but is planned for a future release. To record audio, use the -{@link android.media.MediaRecorder} class. Note that the emulator doesn't have hardware to capture audio, but actual mobile devices are likely to provide these capabilities that you can access through MediaRecorder.

      - -

      For a list of the media formats for which Android offers built-in support, see the Android Media Formats appendix.

      - -

      Playing Audio and Video

      -

      Media can be played from anywhere: from a raw resource, from a file from the system, -or from an available network (URL).

      - -

      You can play back the audio data only to the standard -output device; currently, that is the mobile device speaker or Bluetooth headset. You -cannot play sound files in the conversation audio.

      - -

      Playing from a Raw Resource

      -

      Perhaps the most common thing to want to do is play back media (notably sound) -within your own applications. Doing this is easy:

      -
        -
      1. Put the sound (or other media resource) file into the res/raw - folder of your project, where the Eclipse plugin (or aapt) will find it and - make it into a resource that can be referenced from your R class
      2. -
      3. Create an instance of MediaPlayer, referencing that resource using - {@link android.media.MediaPlayer#create MediaPlayer.create}, and then call - {@link android.media.MediaPlayer#start() start()} on the instance:

      4. -
      -
      -    MediaPlayer mp = MediaPlayer.create(context, R.raw.sound_file_1);
      -    mp.start();
      -
      -

      To stop playback, call {@link android.media.MediaPlayer#stop() stop()}. If -you wish to later replay the media, then you must -{@link android.media.MediaPlayer#reset() reset()} and -{@link android.media.MediaPlayer#prepare() prepare()} the MediaPlayer object -before calling {@link android.media.MediaPlayer#start() start()} again. -(create() calls prepare() the first time.)

      -

      To pause playback, call {@link android.media.MediaPlayer#pause() pause()}. -Resume playback from where you paused with -{@link android.media.MediaPlayer#start() start()}.

      - -

      Playing from a File or Stream

      -

      You can play back media files from the filesystem or a web URL:

      -
        -
      1. Create an instance of the MediaPlayer using new
      2. -
      3. Call {@link android.media.MediaPlayer#setDataSource setDataSource()} - with a String containing the path (local filesystem or URL) - to the file you want to play
      4. -
      5. First {@link android.media.MediaPlayer#prepare prepare()} then - {@link android.media.MediaPlayer#start() start()} on the instance:

      6. -
      -
      -    MediaPlayer mp = new MediaPlayer();
      -    mp.setDataSource(PATH_TO_FILE);
      -    mp.prepare();
      -    mp.start();
      -
      -

      {@link android.media.MediaPlayer#stop() stop()} and -{@link android.media.MediaPlayer#pause() pause()} work the same as discussed -above.

      -

      Note: It is possible that mp could be - null, so good code should null check after the new. - Also, IllegalArgumentException and IOException either - need to be caught or passed on when using setDataSource(), since - the file you are referencing may not exist.

      -

      Note: -If you're passing a URL to an online media file, the file must be capable of -progressive download.

      - -

      Recording Media Resources

      -

      Recording media is a little more involved than playing it back, as you would -probably expect, but it is still fairly simple. There is just a little more set -up to do

      -
        -
      1. Create a new instance of {@link android.media.MediaRecorder - android.media.MediaRecorder} using new
      2. -
      3. Create a new instance of {@link android.content.ContentValues - android.content.ContentValues} and put in some standard properties like - TITLE, TIMESTAMP, and the all important - MIME_TYPE
      4. -
      5. Create a file path for the data to go to (you can use {@link - android.content.ContentResolver android.content.ContentResolver} to - create an entry in the Content database and get it to assign a path - automatically which you can then use)
      6. -
      7. Set the audio source using {@link android.media.MediaRecorder#setAudioSource - MediaRecorder.setAudioSource()}. You will probably want to use - MediaRecorder.AudioSource.MIC
      8. -
      9. Set output file format using {@link - android.media.MediaRecorder#setOutputFormat MediaRecorder.setOutputFormat()} -
      10. -
      11. Set the audio encoder using - {@link android.media.MediaRecorder#setAudioEncoder MediaRecorder.setAudioEncoder()} -
      12. -
      13. Finally, {@link android.media.MediaRecorder#prepare prepare()} and - {@link android.media.MediaRecorder#start start()} the recording. - {@link android.media.MediaRecorder#stop stop()} and - {@link android.media.MediaRecorder#release release()} when you are done
      14. -
      -

      Here is a code example that will hopefully help fill in the gaps:

      -

      Start Recording

      -
      -    recorder = new MediaRecorder();
      -    ContentValues values = new ContentValues(3);
      -
      -    values.put(MediaStore.MediaColumns.TITLE, SOME_NAME_HERE);
      -    values.put(MediaStore.MediaColumns.TIMESTAMP, System.currentTimeMillis());
      -    values.put(MediaStore.MediaColumns.MIME_TYPE, recorder.getMimeContentType());
      -    
      -    ContentResolver contentResolver = new ContentResolver();
      -    
      -    Uri base = MediaStore.Audio.INTERNAL_CONTENT_URI;
      -    Uri newUri = contentResolver.insert(base, values);
      -    
      -    if (newUri == null) {
      -        // need to handle exception here - we were not able to create a new
      -        // content entry
      -    }
      -    
      -    String path = contentResolver.getDataFilePath(newUri);
      -
      -    // could use setPreviewDisplay() to display a preview to suitable View here
      -    
      -    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
      -    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
      -    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
      -    recorder.setOutputFile(path);
      -    
      -    recorder.prepare();
      -    recorder.start();
      -
      -

      Stop Recording

      -
      -    recorder.stop();
      -    recorder.release();
      -
      - diff --git a/docs/html/guide/topics/resources/index.jd b/docs/html/guide/topics/resources/index.jd index 7e3bce42eef95120228502c4f88d53a6838e16c0..1425cfaa1af2f253ad42ecd3486ddf685d2909f4 100644 --- a/docs/html/guide/topics/resources/index.jd +++ b/docs/html/guide/topics/resources/index.jd @@ -18,8 +18,8 @@ In general, these are external elements that you want to include and reference w like images, audio, video, text strings, layouts, themes, etc. Every Android application contains a directory for resources (res/) and a directory for assets (assets/). Assets are used less often, because their applications are far fewer. You only need to save data -as an asset when you need to read the raw bites. -The directories for resources and assets both reside at the top of your project directory, alongside your source code directory +as an asset when you need to read the raw bytes. The directories for resources and assets both +reside at the top of an Android project tree, at the same level as your source code directory (src/).

      The difference between "resources" and "assets" isn't much on the surface, but in general, diff --git a/docs/html/guide/topics/resources/resources-i18n.jd b/docs/html/guide/topics/resources/resources-i18n.jd index b1da4cd6584de3e7dfac9db5535c5617c33bd1d8..4bbb44ac5e5a26fdf9489720b36120a460d41fc6 100644 --- a/docs/html/guide/topics/resources/resources-i18n.jd +++ b/docs/html/guide/topics/resources/resources-i18n.jd @@ -111,21 +111,30 @@ the containing file.

      res/drawable/

      .png, .9.png, .jpg files that are compiled into the following Drawable resource subtypes:

      -

      To get a resource of this type, use Resource.getDrawable(id) -

      +

      To get a resource of this type, use mContext.getResources().getDrawable(R.drawable.imageId)

      +

      Note: Image resources placed in here may + be automatically optimized with lossless image compression by the + aapt tool. For example, a true-color PNG + that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette. + This will result in an image of equal quality but which requires less memory. So be aware that the + image binaries placed in this directory can change during the build. If you plan on reading + an image as a bit stream in order to convert it to a bitmap, put your images in the + res/raw/ folder instead, where they will not be optimized.

      + res/layout/ XML files that are compiled into screen layouts (or part of a screen). - See Declaring Layout + See Declaring Layout. res/values/

      XML files that can be compiled into many kinds of resource.

      -

      Note: unlike the other res/ folders, this one +

      Note: Unlike the other res/ folders, this one can hold any number of files that hold descriptions of resources to create rather than the resources themselves. The XML element types control where these resources are placed under the R class.

      diff --git a/docs/html/guide/topics/ui/custom-components.jd b/docs/html/guide/topics/ui/custom-components.jd index eccc2cac445b7faba53705c696bec7282b4fd1f8..76d103440877940498a3b944767ac3c2d91de3c6 100644 --- a/docs/html/guide/topics/ui/custom-components.jd +++ b/docs/html/guide/topics/ui/custom-components.jd @@ -34,7 +34,7 @@ that you can use to construct your UI.

      {@link android.widget.TextSwitcher TextSwitcher}.

      Among the layouts available are {@link android.widget.LinearLayout LinearLayout}, -{@link android.widget.FrameLayout FrameLayout}, {@link android.widget.AbsoluteLayout AbsoluteLayout}, +{@link android.widget.FrameLayout FrameLayout}, {@link android.widget.RelativeLayout RelativeLayout}, and others. For more examples, see Common Layout Objects.

      If none of the prebuilt widgets or layouts meets your needs, you can create your own View subclass. diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd new file mode 100644 index 0000000000000000000000000000000000000000..c0c0b1bc58da48bd300e2f2d85eb5a985435bfd5 --- /dev/null +++ b/docs/html/guide/topics/ui/dialogs.jd @@ -0,0 +1,650 @@ +page.title=Creating Dialogs +parent.title=User Interface +parent.link=index.html +@jd:body + +

      +
      +

      Key classes

      +
        +
      1. {@link android.app.Dialog}
      2. +
      +

      In this document

      +
        +
      1. Showing a Dialog
      2. +
      3. Dismissing a Dialog
      4. +
      5. Creating an AlertDialog +
          +
        1. Adding buttons
        2. +
        3. Adding a list
        4. +
        +
      6. +
      7. Creating a ProgressDialog +
          +
        1. Showing a progress bar
        2. +
        +
      8. +
      9. Creating a Custom Dialog
      10. +
      +
      +
      + +

      A dialog is usually a small window that appears in front of the current Activity. +The underlying Activity loses focus and the dialog accepts all user interaction. +Dialogs are normally used +for notifications and short activities that directly relate to the application in progress.

      + +

      The Android API supports the following types of {@link android.app.Dialog} objects:

      +
      +
      {@link android.app.AlertDialog}
      +
      A dialog that can manage zero, one, two, or three buttons, and/or a list of + selectable items that can include checkboxes or radio buttons. The AlertDialog + is capable of constructing most dialog user interfaces and is the suggested dialog type. + See Creating an AlertDialog below.
      +
      {@link android.app.ProgressDialog}
      +
      A dialog that displays a progress wheel or progress bar. Because it's an extension of + the AlertDialog, it also supports buttons. + See Creating a ProgressDialog below.
      +
      {@link android.app.DatePickerDialog}
      +
      A dialog that allows the user to select a date. See the + Hello DatePicker tutorial.
      +
      {@link android.app.TimePickerDialog}
      +
      A dialog that allows the user to select a time. See the + Hello TimePicker tutorial.
      +
      + +

      If you would like to customize your own dialog, you can extend the +base {@link android.app.Dialog} object or any of the subclasses listed above and define a new layout. +See the section on Creating a Custom Dialog below.

      + + +

      Showing a Dialog

      + +

      A dialog is always created and displayed as a part of an {@link android.app.Activity}. +You should normally create dialogs from within your Activity's +{@link android.app.Activity#onCreateDialog(int)} callback method. +When you use this callback, the Android system automatically manages the state of +each dialog and hooks them to the Activity, effectively making it the "owner" of each dialog. +As such, each dialog inherits certain properties from the Activity. For example, when a dialog +is open, the Menu key reveals the options menu defined for the Activity and the volume +keys modify the audio stream used by the Activity.

      + +

      Note: If you decide to create a dialog outside of the +onCreateDialog() method, it will not be attached to an Activity. You can, however, +attach it to an Activity with {@link android.app.Dialog#setOwnerActivity(Activity)}.

      + +

      When you want to show a dialog, call +{@link android.app.Activity#showDialog(int)} and pass it an integer that uniquely identifies the +dialog that you want to display.

      + +

      When a dialog is requested for the first time, Android calls +{@link android.app.Activity#onCreateDialog(int)} from your Activity, which is +where you should instantiate the {@link android.app.Dialog}. This callback method +is passed the same ID that you passed to {@link android.app.Activity#showDialog(int)}. +After you create the Dialog, return the object at the end of the method.

      + +

      Before the dialog is displayed, Android also calls the optional callback method +{@link android.app.Activity#onPrepareDialog(int,Dialog)}. Define this method if you want to change +any properties of the dialog each time it is opened. This method is called +every time a dialog is opened, whereas {@link android.app.Activity#onCreateDialog(int)} is only +called the very first time a dialog is opened. If you don't define +{@link android.app.Activity#onPrepareDialog(int,Dialog) onPrepareDialog()}, then the dialog will +remain the same as it was the previous time it was opened. This method is also passed the dialog's +ID, along with the Dialog object you created in {@link android.app.Activity#onCreateDialog(int) +onCreateDialog()}.

      + +

      The best way to define the {@link android.app.Activity#onCreateDialog(int)} and +{@link android.app.Activity#onPrepareDialog(int,Dialog)} callback methods is with a +switch statement that checks the id parameter that's passed into the method. +Each case should check for a unique dialog ID and then create and define the respective Dialog. +For example, imagine a game that uses two different dialogs: one to indicate that the game +has paused and another to indicate that the game is over. First, define an integer ID for +each dialog:

      +
      +static final int DIALOG_PAUSED_ID = 0;
      +static final int DIALOG_GAMEOVER_ID = 1;
      +
      + +

      Then, define the {@link android.app.Activity#onCreateDialog(int)} callback with a +switch case for each ID:

      +
      +protected Dialog onCreateDialog(int id) {
      +    Dialog dialog;
      +    switch(id) {
      +    case DIALOG_PAUSED_ID:
      +        // do the work to define the pause Dialog
      +        break;
      +    case DIALOG_GAMEOVER_ID:
      +        // do the work to define the game over Dialog
      +        break;
      +    default:
      +        dialog = null;
      +    }
      +    return dialog;
      +}
      +
      + +

      Note: In this example, there's no code inside +the case statements because the procedure for defining your Dialog is outside the scope +of this section. See the section below about Creating an AlertDialog, +offers code suitable for this example.

      + +

      When it's time to show one of the dialogs, call {@link android.app.Activity#showDialog(int)} +with the ID of a dialog:

      +
      +showDialog(DIALOG_PAUSED_ID);
      +
      + + +

      Dismissing a Dialog

      + +

      When you're ready to close your dialog, you can dismiss it by calling +{@link android.app.Dialog#dismiss()} on the Dialog object. +If necessary, you can also call {@link android.app.Activity#dismissDialog(int)} from the +Activity, which effectively calls {@link android.app.Dialog#dismiss()} on the +Dialog for you.

      + +

      If you are using {@link android.app.Activity#onCreateDialog(int)} to manage the state +of your dialogs (as discussed in the previous section), then every time your dialog is +dismissed, the state of the Dialog +object is retained by the Activity. If you decide that you will no longer need this object or +it's important that the state is cleared, then you should call +{@link android.app.Activity#removeDialog(int)}. This will remove any internal references +to the object and if the dialog is showing, it will dismiss it.

      + +

      Using dismiss listeners

      + +

      If you'd like your applcation to perform some procedures the moment that a dialog is dismissed, +then you should attach an on-dismiss listener to your Dialog.

      + +

      First define the {@link android.content.DialogInterface.OnDismissListener} interface. +This interface has just one method, +{@link android.content.DialogInterface.OnDismissListener#onDismiss(DialogInterface)}, which +will be called when the dialog is dismissed. +Then simply pass your OnDismissListener implementation to +{@link android.app.Dialog#setOnDismissListener(DialogInterface.OnDismissListener) +setOnDismissListener()}.

      + +

      However, note that dialogs can also be "cancelled." This is a special case that indicates +the dialog was explicitly cancelled by the user. This will occur if the user presses the +"back" button to close the dialog, or if the dialog explicitly calls {@link android.app.Dialog#cancel()} +(perhaps from a "Cancel" button in the dialog). When a dialog is cancelled, +the OnDismissListener will still be notified, but if you'd like to be informed that the dialog +was explicitly cancelled (and not dismissed normally), then you should register +an {@link android.content.DialogInterface.OnCancelListener} with +{@link android.app.Dialog#setOnCancelListener(DialogInterface.OnCancelListener) +setOnCancelListener()}.

      + + +

      Creating an AlertDialog

      + +

      An {@link android.app.AlertDialog} is an extension of the {@link android.app.Dialog} +class. It is capable of constructing most dialog user interfaces and is the suggested dialog type. +You should use it for dialogs that use any of the following features:

      +
        +
      • A title
      • +
      • A text message
      • +
      • One, two, or three buttons
      • +
      • A list of selectable items (with optional checkboxes or radio buttons)
      • +
      + +

      To create an AlertDialog, use the {@link android.app.AlertDialog.Builder} subclass. +Get a Builder with {@link android.app.AlertDialog.Builder#AlertDialog.Builder(Context)} and +then use the class's public methods to define all of the +AlertDialog properties. After you're done with the Builder, retrieve the +AlertDialog object with {@link android.app.AlertDialog.Builder#create()}.

      + +

      The following topics show how to define various properties of the AlertDialog using the +AlertDialog.Builder class. If you use any of the following sample code inside your +{@link android.app.Activity#onCreateDialog(int) onCreateDialog()} callback method, +you can return the resulting Dialog object to display the dialog.

      + + +

      Adding buttons

      + + + +

      To create an AlertDialog with side-by-side buttons like the one shown in the screenshot to the right, +use the set...Button() methods:

      + +
      +AlertDialog.Builder builder = new AlertDialog.Builder(this);
      +builder.setMessage("Are you sure you want to exit?")
      +       .setCancelable(false)
      +       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
      +           public void onClick(DialogInterface dialog, int id) {
      +                MyActivity.this.finish();
      +           }
      +       })
      +       .setNegativeButton("No", new DialogInterface.OnClickListener() {
      +           public void onClick(DialogInterface dialog, int id) {
      +                dialog.cancel();
      +           }
      +       });
      +AlertDialog alert = builder.create();
      +
      + +

      First, add a message for the dialog with +{@link android.app.AlertDialog.Builder#setMessage(CharSequence)}. Then, begin +method-chaining and set the dialog +to be not cancelable (so the user cannot close the dialog with the back button) +with {@link android.app.AlertDialog.Builder#setCancelable(boolean)}. For each button, +use one of the set...Button() methods, such as +{@link android.app.AlertDialog.Builder#setPositiveButton(CharSequence,DialogInterface.OnClickListener) +setPositiveButton()}, that accepts the name for the button and a +{@link android.content.DialogInterface.OnClickListener} that defines the action to take +when the user selects the button.

      + +

      Note: You can only add one of each button type to the +AlertDialog. That is, you cannot have more than one "positive" button. This limits the number +of possible buttons to three: positive, neutral, and negative. These names are technically irrelevant to the +actual functionality of your buttons, but should help you keep track of which one does what.

      + + +

      Adding a list

      + + + +

      To create an AlertDialog with a list of selectable items like the one shown to the right, +use the setItems() method:

      + +
      +final CharSequence[] items = {"Red", "Green", "Blue"};
      +
      +AlertDialog.Builder builder = new AlertDialog.Builder(this);
      +builder.setTitle("Pick a color");
      +builder.setItems(items, new DialogInterface.OnClickListener() {
      +    public void onClick(DialogInterface dialog, int item) {
      +        Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
      +    }
      +});
      +AlertDialog alert = builder.create();
      +
      + +

      First, add a title to the dialog with +{@link android.app.AlertDialog.Builder#setTitle(CharSequence)}. +Then, add a list of selectable items with +{@link android.app.AlertDialog.Builder#setItems(CharSequence[],DialogInterface.OnClickListener) +setItems()}, which accepts the array of items to display and a +{@link android.content.DialogInterface.OnClickListener} that defines the action to take +when the user selects an item.

      + + +

      Adding checkboxes and radio buttons

      + + + +

      To create a list of multiple-choice items (checkboxes) or +single-choice items (radio buttons) inside the dialog, use the +{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String, +DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()} and +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} methods, respectively. +If you create one of these selectable lists in the +{@link android.app.Activity#onCreateDialog(int) onCreateDialog()} callback method, +Android manages the state of the list for you. As long as the Activity is active, +the dialog remembers the items that were previously selected, but when the user exits the +Activity, the selection is lost. + +

      Note: To save the selection when the user leaves or +pauses the Activity, you must properly save and restore the setting throughout +the Activity Lifecycle. +To permanently save the selections, even when the Activity process is completely shutdown, +you need to save the settings +with one of the Data +Storage techniques.

      + +

      To create an AlertDialog with a list of single-choice items like the one shown to the right, +use the same code from the previous example, but replace the setItems() method with +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()}:

      + +
      +final CharSequence[] items = {"Red", "Green", "Blue"};
      +
      +AlertDialog.Builder builder = new AlertDialog.Builder(this);
      +builder.setTitle("Pick a color");
      +builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
      +    public void onClick(DialogInterface dialog, int item) {
      +        Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
      +    }
      +});
      +AlertDialog alert = builder.create();
      +
      + +

      The second parameter in the +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(CharSequence[],int,DialogInterface.OnClickListener) +setSingleChoiceItems()} method is an integer value for the checkedItem, which indicates the +zero-based list position of the default selected item. Use "-1" to indicate that no item should be +selected by default.

      + + +

      Creating a ProgressDialog

      + + + +

      A {@link android.app.ProgressDialog} is an extension of the {@link android.app.AlertDialog} +class that can display a progress animation in the form of a spinning wheel, for a task with +progress that's undefined, or a progress bar, for a task that has a defined progression. +The dialog can also provide buttons, such as one to cancel a download.

      + +

      Opening a progress dialog can be as simple as calling +{@link android.app.ProgressDialog#show(Context,CharSequence,CharSequence) +ProgressDialog.show()}. For example, the progress dialog shown to the right can be +easily achieved without managing the dialog through the +{@link android.app.Activity#onCreateDialog(int)} callback, +as shown here:

      + +
      +ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "", 
      +                        "Loading. Please wait...", true);
      +
      + +

      The first parameter is the application {@link android.content.Context}, +the second is a title for the dialog (left empty), the third is the message, +and the last parameter is whether the progress +is indeterminate (this is only relevant when creating a progress bar, which is +discussed in the next section). +

      + +

      The default style of a progress dialog is the spinning wheel. +If you want to create a progress bar that shows the loading progress with granularity, +some more code is required, as discussed in the next section.

      + + +

      Showing a progress bar

      + + + +

      To show the progression with an animated progress bar:

      + +
        +
      1. Initialize the + ProgressDialog with the class constructor, + {@link android.app.ProgressDialog#ProgressDialog(Context)}.
      2. +
      3. Set the progress style to "STYLE_HORIZONTAL" with + {@link android.app.ProgressDialog#setProgressStyle(int)} and + set any other properties, such as the message.
      4. +
      5. When you're ready to show the dialog, call + {@link android.app.Dialog#show()} or return the ProgressDialog from the + {@link android.app.Activity#onCreateDialog(int)} callback.
      6. +
      7. You can increment the amount of progress displayed + in the bar by calling either {@link android.app.ProgressDialog#setProgress(int)} with a value for + the total percentage completed so far or {@link android.app.ProgressDialog#incrementProgressBy(int)} + with an incremental value to add to the total percentage completed so far.
      8. +
      + +

      For example, your setup might look like this:

      +
      +ProgressDialog progressDialog;
      +progressDialog = new ProgressDialog(mContext);
      +progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      +progressDialog.setMessage("Loading...");
      +progressDialog.setCancelable(false);
      +
      + +

      The setup is simple. Most of the code needed to create a progress dialog is actually +involved in the process that updates it. You might find that it's +necessary to create a second thread in your application for this work and then report the progress +back to the Activity's UI thread with a {@link android.os.Handler} object. +If you're not familiar with using additional +threads with a Handler, see the example Activity below that uses a second thread to +increment a progress dialog managed by the Activity.

      + + + + +
      + + + Example ProgressDialog with a second thread +
      +

      This example uses a second thread to track the progress of a process (which actually just +counts up to 100). The thread sends a {@link android.os.Message} back to the main +Activity through a {@link android.os.Handler} each time progress is made. The main Activity then updates the +ProgressDialog.

      + +
      +package com.example.progressdialog;
      +
      +import android.app.Activity;
      +import android.app.Dialog;
      +import android.app.ProgressDialog;
      +import android.os.Bundle;
      +import android.os.Handler;
      +import android.os.Message;
      +import android.view.View;
      +import android.view.View.OnClickListener;
      +import android.widget.Button;
      +
      +public class NotificationTest extends Activity {
      +    static final int PROGRESS_DIALOG = 0;
      +    Button button;
      +    ProgressThread progressThread;
      +    ProgressDialog progressDialog;
      +   
      +    /** Called when the activity is first created. */
      +    public void onCreate(Bundle savedInstanceState) {
      +        super.onCreate(savedInstanceState);
      +        setContentView(R.layout.main);
      +
      +        // Setup the button that starts the progress dialog
      +        button = (Button) findViewById(R.id.progressDialog);
      +        button.setOnClickListener(new OnClickListener(){
      +            public void onClick(View v) {
      +                showDialog(PROGRESS_DIALOG);
      +            }
      +        }); 
      +    }
      +   
      +    protected Dialog onCreateDialog(int id) {
      +        switch(id) {
      +        case PROGRESS_DIALOG:
      +            progressDialog = new ProgressDialog(NotificationTest.this);
      +            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      +            progressDialog.setMessage("Loading...");
      +            progressThread = new ProgressThread(handler);
      +            progressThread.start();
      +            return progressDialog;
      +        default:
      +            return null;
      +        }
      +    }
      +
      +    // Define the Handler that receives messages from the thread and update the progress
      +    final Handler handler = new Handler() {
      +        public void handleMessage(Message msg) {
      +            int total = msg.getData().getInt("total");
      +            progressDialog.setProgress(total);
      +            if (total >= 100){
      +                dismissDialog(PROGRESS_DIALOG);
      +                progressThread.setState(ProgressThread.STATE_DONE);
      +            }
      +        }
      +    };
      +
      +    /** Nested class that performs progress calculations (counting) */
      +    private class ProgressThread extends Thread {
      +        Handler mHandler;
      +        final static int STATE_DONE = 0;
      +        final static int STATE_RUNNING = 1;
      +        int mState;
      +        int total;
      +       
      +        ProgressThread(Handler h) {
      +            mHandler = h;
      +        }
      +       
      +        public void run() {
      +            mState = STATE_RUNNING;   
      +            total = 0;
      +            while (mState == STATE_RUNNING) {
      +                try {
      +                    Thread.sleep(100);
      +                } catch (InterruptedException e) {
      +                    Log.e("ERROR", "Thread Interrupted");
      +                }
      +                Message msg = mHandler.obtainMessage();
      +                Bundle b = new Bundle();
      +                b.putInt("total", total);
      +                msg.setData(b);
      +                mHandler.sendMessage(msg);
      +                total++;
      +            }
      +        }
      +        
      +        /* sets the current state for the thread,
      +         * used to stop the thread */
      +        public void setState(int state) {
      +            mState = state;
      +        }
      +    }
      +}
      +
      +
      +
      + + + +

      Creating a Custom Dialog

      + + + +

      If you want a customized design for a dialog, you can create your own layout +for the dialog window with layout and widget elements. +After you've defined your layout, pass the root View object or +layout resource ID to {@link android.app.Dialog#setContentView(View)}.

      + +

      For example, to create the dialog shown to the right:

      + +
        +
      1. Create an XML layout saved as custom_dialog.xml: +
        +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        +              android:id="@+id/layout_root"
        +              android:orientation="horizontal"
        +              android:layout_width="fill_parent"
        +              android:layout_height="fill_parent"
        +              android:padding="10dp"
        +              >
        +    <ImageView android:id="@+id/image"
        +               android:layout_width="wrap_content"
        +               android:layout_height="fill_parent"
        +               android:layout_marginRight="10dp"
        +               />
        +    <TextView android:id="@+id/text"
        +              android:layout_width="wrap_content"
        +              android:layout_height="fill_parent"
        +              android:textColor="#FFF"
        +              />
        +</LinearLayout>
        +
        + +

        This XML defines an {@link android.widget.ImageView} and a {@link android.widget.TextView} + inside a {@link android.widget.LinearLayout}.

        +
      2. Set the above layout as the dialog's content view and define the content + for the ImageView and TextView elements:

        +
        +Context mContext = getApplicationContext();
        +Dialog dialog = new Dialog(mContext);
        +
        +dialog.setContentView(R.layout.custom_dialog);
        +dialog.setTitle("Custom Dialog");
        +
        +TextView text = (TextView) dialog.findViewById(R.id.text);
        +text.setText("Hello, this is a custom dialog!");
        +ImageView image = (ImageView) dialog.findViewById(R.id.image);
        +image.setImageResource(R.drawable.android);
        +
        + +

        After you instantiate the Dialog, set your custom layout as the dialog's content view with + {@link android.app.Dialog#setContentView(int)}, passing it the layout resource ID. + Now that the Dialog has a defined layout, you can capture View objects from the layout with + {@link android.app.Dialog#findViewById(int)} and modify their content.

        +
      3. + +
      4. That's it. You can now show the dialog as described in + Showing A Dialog.
      5. +
      + +

      A dialog made with the base Dialog class must have a title. If you don't call +{@link android.app.Dialog#setTitle(CharSequence) setTitle()}, then the space used for the title +remains empty, but still visible. If you don't want +a title at all, then you should create your custom dialog using the +{@link android.app.AlertDialog} class. However, because an AlertDialog is created easiest with +the {@link android.app.AlertDialog.Builder} class, you do not have access to the +{@link android.app.Dialog#setContentView(int)} method used above. Instead, you must use +{@link android.app.AlertDialog.Builder#setView(View)}. This method accepts a {@link android.view.View} object, +so you need to inflate the layout's root View object from +XML.

      + +

      To inflate the XML layout, retrieve the {@link android.view.LayoutInflater} with +{@link android.app.Activity#getLayoutInflater()} +(or {@link android.content.Context#getSystemService(String) getSystemService()}), +and then call +{@link android.view.LayoutInflater#inflate(int, ViewGroup)}, where the first parameter +is the layout resource ID and the second is the ID of the root View. At this point, you can use +the inflated layout to find View objects in the layout and define the content for the +ImageView and TextView elements. Then instantiate the AlertDialog.Builder and set the +inflated layout for the dialog with {@link android.app.AlertDialog.Builder#setView(View)}.

      + +

      Here's an example, creating a custom layout in an AlertDialog:

      + +
      +AlertDialog.Builder builder;
      +AlertDialog alertDialog;
      +
      +Context mContext = getApplicationContext();
      +LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER);
      +View layout = inflater.inflate(R.layout.custom_dialog,
      +                               (ViewGroup) findViewById(R.id.layout_root));
      +
      +TextView text = (TextView) layout.findViewById(R.id.text);
      +text.setText("Hello, this is a custom dialog!");
      +ImageView image = (ImageView) layout.findViewById(R.id.image);
      +image.setImageResource(R.drawable.android);
      +
      +builder = new AlertDialog.Builder(mContext);
      +builder.setView(layout);
      +alertDialog = builder.create();
      +
      + +

      Using an AlertDialog for your custom layout lets you +take advantage of built-in AlertDialog features like managed buttons, +selectable lists, a title, an icon and so on.

      + +

      For more information, refer to the reference documentation for the +{@link android.app.Dialog} and {@link android.app.AlertDialog.Builder} +classes.

      + + + diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd index a511005c7929785c33e35636ad0efd12b2d45c2b..21f98338495461dcef704c4598f3554e2af87e74 100644 --- a/docs/html/guide/topics/ui/how-android-draws.jd +++ b/docs/html/guide/topics/ui/how-android-draws.jd @@ -70,8 +70,8 @@ and each View is responsible for drawing itself. enclose its content (plus padding).

      There are subclasses of LayoutParams for different subclasses of ViewGroup. - For example, AbsoluteLayout has its own subclass of LayoutParams which adds - an X and Y value. + For example, RelativeLayout has its own subclass of LayoutParams, which includes + the ability to center child Views horizontally and vertically.

      diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd index 6bd1d1534298fab8436cb7597dd6c9e077a267b3..ef23672c836ac929c8708257bc55bc1d095bac9e 100644 --- a/docs/html/guide/topics/ui/index.jd +++ b/docs/html/guide/topics/ui/index.jd @@ -116,7 +116,7 @@ complex layout.

      There are a variety of ways in which you can layout your views. Using more and different kinds of view groups, you can structure child views and view groups in an infinite number of ways. -Some pre-defined view groups offered by Android (called layouts) include LinearLayout, RelativeLayout, AbsoluteLayout, +Some pre-defined view groups offered by Android (called layouts) include LinearLayout, RelativeLayout, TableLayout, GridLayout and others. Each offers a unique set of layout parameters that are used to define the positions of child views and layout structure.

      To learn about some of the different kinds of view groups used for a layout, diff --git a/docs/html/guide/topics/ui/layout-objects.jd b/docs/html/guide/topics/ui/layout-objects.jd index cf85fd62b962e88238ce711bdd454ce8cbda1daf..bb13a188e833cc4a24b80f84833d7eb3a9cf38e2 100644 --- a/docs/html/guide/topics/ui/layout-objects.jd +++ b/docs/html/guide/topics/ui/layout-objects.jd @@ -10,7 +10,6 @@ parent.link=index.html

    1. FrameLayout
    2. LinearLayout
    3. TableLayout
    4. -
    5. AbsoluteLayout
    6. RelativeLayout
    7. Summary of Important View Groups
    @@ -143,16 +142,6 @@ documentation for more details.

    TableLayout tutorial.

    -

    AbsoluteLayout

    -

    {@link android.widget.AbsoluteLayout} enables child views to specify - their own exact x/y coordinates on the screen. Coordinates (0,0) is the upper left - corner, and values increase as you move down and to the right. Margins are not - supported, and overlapping elements are allowed (although not recommended). We - generally recommend against using AbsoluteLayout unless you have good reasons - to use it, because it is fairly rigid and does not adjust to different types of - displays.

    - -

    RelativeLayout

    {@link android.widget.RelativeLayout} lets child views specify their position relative to the parent view or to each other (specified by ID). So you can @@ -231,11 +220,6 @@ RelativeLayout tutorial.

    Class Description - - {@link android.widget.AbsoluteLayout AbsoluteLayout}
    - Enables you to specify the location of child objects relative to the - parent in exact measurements (for example, pixels). - {@link android.widget.FrameLayout FrameLayout} Layout that acts as a view frame to display diff --git a/docs/html/guide/topics/ui/notifiers/index.jd b/docs/html/guide/topics/ui/notifiers/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..5b37f5b623aa5625c9b19162c9a4d5d30240372b --- /dev/null +++ b/docs/html/guide/topics/ui/notifiers/index.jd @@ -0,0 +1,107 @@ +page.title=Notifying the User +@jd:body + + + +

    Several types of situations may arise that require you to notify the user +about an event that occurs in your application. Some events require the user to respond +and others do not. For example:

    +
      +
    • When an event such as saving a file is complete, a small message +should appear to confirm that the save was successful.
    • +
    • If the application is running in the background and needs the user's attention, +the application should create a notificaiton that allows the user to respond at +his or her convenience.
    • +
    • If the application is +performing work that the user must wait for (such as loading a file), +the application should show a hovering progress wheel or bar.
    • +
    + +

    Each of these notification tasks can be achieved using a different technique:

    + + +

    This document summarizes each of these techniques for notifying the user and includes +links to full documentation.

    + + +

    Toast Notification

    + + + +

    A toast notificaiton is a message that pops up on the surface of the window. +It only fills the amount of space required for the message and the user's current +activity remains visible and interactive. The notification automatically fades in and +out, and does not accept interaction events. Because a toast can be created from a background +{@link android.app.Service}, it appears even if the application isn't visible.

    + +

    A toast is best for short text messages, such as "File saved," +when you're fairly certain the user is paying attention +to the screen. A toast can not accept user interaction events; if you'd like +the user to respond and take action, consider using a +Status Bar Notification instead.

    + +

    For more information, refer to Creating Toast Notifications.

    + + +

    Status Bar Notification

    + + + +

    A status bar notification adds an icon to the system's status bar +(with an optional ticker-text message) and an expanded message in the "Notifications" window. +When the user selects the expanded message, Android fires an +{@link android.content.Intent} that is defined by the notification (usually to launch an +{@link android.app.Activity}). +You can also configure the notification to alert the user with a sound, a vibration, and flashing +lights on the device.

    + +

    This kind of notification is ideal when your application is working in +a background {@link android.app.Service} and needs to +notify the user about an event. If you need to alert the user about an event that occurs +while your Activity is still in focus, consider using a +Dialog Notification instead.

    + +

    For more information, refer to +Creating Status Bar Notifications.

    + + +

    Dialog Notification

    + + + +

    A dialog is usually a small window that appears in front of the current Activity. +The underlying Activity loses focus and the dialog accepts all user interaction. +Dialogs are normally used +for notifications and short activities that directly relate to the application in progress.

    + +

    You should use a dialog when you need to show a progress bar or a short +message that requires confirmation from the user (such as an alert with "OK" and "Cancel" buttons). +You can use also use dialogs as integral componenents +in your application's UI and for other purposes besides notifications. +For a complete discussion on all the available types of dialogs, +including its uses for notifications, refer to +Creating Dialogs.

    + + + diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd new file mode 100644 index 0000000000000000000000000000000000000000..e6fa48fe2385ace3af4d60d110025e62bcbe9805 --- /dev/null +++ b/docs/html/guide/topics/ui/notifiers/notifications.jd @@ -0,0 +1,432 @@ +page.title=Creating Status Bar Notifications +parent.title=Notifying the User +parent.link=index.html +@jd:body + +
    +
    +

    Key classes

    +
      +
    1. {@link android.app.Notification}
    2. +
    3. {@link android.app.NotificationManager}
    4. +
    +

    In this document

    +
      +
    1. The Basics
    2. +
    3. Managing your Notifications
    4. +
    5. Creating a Notification +
        +
      1. Updating the notification
      2. +
      3. Adding a sound
      4. +
      5. Adding vibration
      6. +
      7. Adding flashing lights
      8. +
      9. More features
      10. +
      +
    6. +
    7. Creating a Custom Expanded View
    8. +
    +
    +
    + +

    A status bar notification adds an icon to the system's status bar +(with an optional ticker-text message) and an expanded message in the "Notifications" window. +When the user selects the expanded message, Android fires an +{@link android.content.Intent} that is defined by the notification (usually to launch an +{@link android.app.Activity}). +You can also configure the notification to alert the user with a sound, a vibration, and flashing +lights on the device.

    + +

    A status bar notification should be used for any case in +which a background Service needs to alert the user about an event that requires a response. A background Service +should never launch an Activity on its own in order to receive user interaction. +The Service should instead create a status bar notification that will launch the Activity +when selected by the user.

    + +

    The screenshot below shows the status bar with a notification icon on the left side.

    + + +

    The next screenshot shows the notification's expanded message in the "Notifications" window. +The user can reveal the Notifications window by pulling down the status bar +(or selecting Notifications from the Home options menu).

    + + + +

    The Basics

    + +

    An {@link android.app.Activity} or {@link android.app.Service} can initiate a status bar +notification. Because an Activity can perform actions only while it is +active and in focus, you should create your status bar notifications from a +Service. This way, the notification can be created from the background, +while the user is using another application or +while the device is asleep. To create a notification, you must use two +classes: {@link android.app.Notification} and {@link android.app.NotificationManager}.

    + +

    Use an instance of the {@link android.app.Notification} class to define the properties of your +status bar notification, such as the status bar icon, the expanded message, and extra settings such +as a sound to play. The {@link android.app.NotificationManager} is an Android system service that +executes and manages all Notifications. You do not instantiate the NotificationManager. In order +to give it your Notification, you must retrieve a reference to the NotificationManager with +{@link android.app.Activity#getSystemService(String) getSystemService()} and +then, when you want to notify the user, pass it your Notification object with +{@link android.app.NotificationManager#notify(int,Notification) notify()}.

    + +

    To create a status bar notification:

    +
      +
    1. Get a reference to the NotificationManager: +
      +String ns = Context.NOTIFICATION_SERVICE;
      +NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
      +
      +
    2. +
    3. Instantiate the Notification: +
      +int icon = R.drawable.notification_icon;
      +CharSequence tickerText = "Hello";
      +long when = System.currentTimeMillis();
      +
      +Notification notification = new Notification(icon, tickerText, when);
      +
      +
    4. +
    5. Define the Notification's expanded message and Intent: +
      +Context context = getApplicationContext();
      +CharSequence contentTitle = "My notification";
      +CharSequence contentText = "Hello World!";
      +Intent notificationIntent = new Intent(this, MyClass.class);
      +PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
      +
      +notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
      +
      +
    6. +
    7. Pass the Notification to the NotificationManager: +
      +private static final int HELLO_ID = 1;
      +
      +mNotificationManager.notify(HELLO_ID, notification);
      +
      +

      That's it. Your user has now been notified.

      +
    8. +
    + + +

    Managing your Notifications

    + +

    The {@link android.app.NotificationManager} is a system service that manages all +notifications. You must retrieve a reference to it with the +{@link android.app.Activity#getSystemService(String) getSystemService()} method. +For example:

    +
    +String ns = Context.NOTIFICATION_SERVICE;
    +NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
    +
    + +

    When you want to send your status bar notification, pass the Notification object +to the NotificationManager with {@link android.app.NotificationManager#notify(int,Notification)}. +The first parameter is the unique ID for the Notification and the second is the Notification object. +The ID uniquely identifies the Notification from within your +application. This is necessary if you need to update the Notification or (if +your application manages different kinds of Notifications) select the appropriate action +when the user returns to your application via the Intent defined in the Notification.

    + +

    To clear the status bar notification when the user selects it from the Notifications +window, add the "FLAG_AUTO_CANCEL" flag to your Notification object. You can also clear it +manually with {@link android.app.NotificationManager#cancel(int)}, passing it the notification ID, +or clear all your Notifications with {@link android.app.NotificationManager#cancelAll()}.

    + + +

    Creating a Notification

    + +

    A {@link android.app.Notification} object defines the details of the notification +message that is displayed in the status bar and "Notifications" window, and any other +alert settings, such as sounds and blinking lights.

    + +

    A status bar notification requires all of the following:

    +
      +
    • An icon for the status bar
    • +
    • A title and expanded message for the expanded view (unless you define a + custom expanded view)
    • +
    • A {@link android.app.PendingIntent}, to be fired when the notification is selected
    • +
    +

    Optional settings for the status bar notification include:

    +
      +
    • A ticker-text message for the status bar
    • +
    • An alert sound
    • +
    • A vibrate setting
    • +
    • A flashing LED setting
    • +
    + +

    The starter-kit for a new Notification includes the +{@link android.app.Notification#Notification(int,CharSequence,long)} constructor and the +{@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent)} +method. These define all the required settings for a Notification. +The following snippet demonstrates a basic Notification setup:

    +
    +int icon = R.drawable.notification_icon;        // icon from resources
    +CharSequence tickerText = "Hello";              // ticker-text
    +long when = System.currentTimeMillis();         // notification time
    +Context context = getApplicationContext();      // application Context
    +CharSequence contentTitle = "My notification";  // expanded message title
    +CharSequence contentText = "Hello World!";      // expanded message text
    +
    +Intent notificationIntent = new Intent(this, MyClass.class);
    +PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    +
    +// the next two lines initialize the Notification, using the configurations above
    +Notification notification = new Notification(icon, tickerText, when);
    +notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
    +
    + + +

    Updating the notification

    + +

    You can update the information in your status bar notification as events +continue to occur in your application. For example, when a new SMS text message arrives +before previous messages have been read, the Messaging application updates the existing +notification to display the total number of new messages received. +This practice of updating an existing Notification is much better than adding new Notifications +to the NotificationManager because it avoids clutter in the Notifications window.

    + +

    Because each notification is uniquely identified +by the NotificationManager with an integer ID, you can revise the notification by calling +{@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) +setLatestEventInfo()} with new values, change some field values of the Notification, and then call +{@link android.app.NotificationManager#notify(int,Notification) notify()} again.

    + +

    You can revise each property with the object member fields +(except for the Context and the expanded message title and text). You should always +revise the text message when you update the notification by calling +{@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) +setLatestEventInfo()} with new values for contentTitle and contentText. +Then call {@link android.app.NotificationManager#notify(int,Notification) notify()} to update the +notification. (Of course, if you've created a custom expanded +view, then updating these title and text values has no effect.)

    + + +

    Adding a sound

    + +

    You can alert the user with the default notification sound +(which is defined by the user) or with a sound specified by your application.

    + +

    To use the user's default sound, add "DEFAULT_SOUND" to the defaults field:

    +
    +notification.defaults |= Notification.DEFAULT_SOUND;
    +
    + +

    To use a different sound with your notifications, pass a Uri reference to the +sound field. +The following example uses a known audio file saved to the device SD card:

    +
    +notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3");
    +
    + +

    In the next example, the audio file is chosen from the internal +{@link android.provider.MediaStore.Audio.Media MediaStore}'s {@link android.content.ContentProvider}:

    +
    +notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");
    +
    + +

    In this case, the exact ID of the media file ("6") is known and appended to the content +{@link android.net.Uri}. If you don't know the exact ID, you must query all the +media available in the MediaStore with a {@link android.content.ContentResolver}. +See the Content Providers +documentation for more information on using a ContentResolver.

    + +

    If you want the sound to continuously repeat until the user responds to the notification +or the notification is cancelled, add "FLAG_INSISTENT" to the flags field.

    + +

    Note: If the defaults field includes +"DEFAULT_SOUND", then the default sound overrides any sound defined by the sound field.

    + + +

    Adding vibration

    + +

    You can alert the user with the the default +vibration pattern or with a vibration pattern defined by your application.

    + +

    To use the default pattern, add "DEFAULT_VIBRATE" to the defaults field:

    +
    +notification.defaults |= Notification.DEFAULT_VIBRATE;
    +
    + +

    To define your own vibration pattern, pass an array of long values to the +vibrate field:

    +
    +long[] vibrate = {0,100,200,300};
    +notification.vibrate = vibrate;
    +
    + +

    The long array defines the alternating pattern for the length of vibration off and on +(in milliseconds). The first value is how long to wait (off) before beginning, the second +value is the length of the first vibration, the third is the next length off, and so on. +The pattern can be as long as you like, but it can't be set to repeat. +

    + +

    Note: If the defaults field includes +"DEFAULT_VIBRATE", then the default vibration overrides any vibration defined by the +vibrate field.

    + + +

    Adding flashing lights

    + +

    To alert the user by flashing LED lights, you can implement the default +light pattern (if available), or define your own color and pattern for the lights.

    + +

    To use the default light setting, add "DEFAULT_LIGHTS" to the defaults field:

    +
    +notification.defaults |= Notification.DEFAULT_LIGHTS;
    +
    + +

    To define your own color and pattern, define a value for the ledARGB field +(for the color), the ledOffMS field (length of time, in milliseconds, to +keep the light off), the ledOnMS (length of time, in milliseconds, to keep the light on), +and also add "FLAG_SHOW_LIGHTS" to the flags field:

    +
    +notification.ledARGB = 0xff00ff00;
    +notification.ledOnMS = 300;
    +notification.ledOffMS = 1000;
    +notification.flags |= Notification.FLAG_SHOW_LIGHTS;
    +
    + +

    In this example, the green light repeatedly flashes on for 300 milliseconds and +turns off for one second. Not every color in the spectrum is supported by the +device LEDs, and not every device supports the same colors, so the hardware +estimates to the best of its ability. Green is the most common notification color.

    + + +

    More features

    + +

    You can add several more features to your notifications +using Notification fields and flags. Some useful features include the following:

    + +
    +
    "FLAG_AUTO_CANCEL" flag
    +
    Add this to the flags field to automatically cancel the notification + after it is selected from the Notifications window.
    +
    "FLAG_INSISTENT" flag
    +
    Add this to the flags field to repeat the audio until the + user responds.
    +
    "FLAG_ONGOING_EVENT" flag
    +
    Add this to the flags field to group the notification under the "Ongoing" + title in the Notifications window. This indicates that the application is on-going — + its processes is still running in the background, even when the application is not + visible (such as with music or a phone call).
    +
    "FLAG_NO_CLEAR" flag
    +
    Add this to the flags field to indicate that the notification should + not be cleared by the "Clear notifications" button. This is particularly useful if + your notification is on-going.
    +
    number field
    +
    This value indicates the current number of events represented by the notification. + The appropriate number is overlayed on top of the status bar icon. + If you intend to use this field, then you must start with "1" when the Notification is first + created. (If you change the value from zero to anything greater during an update, the number + is not shown.)
    +
    iconLevel field
    +
    This value indicates the current level of a + {@link android.graphics.drawable.LevelListDrawable} that is used for the notification icon. + You can animate the icon in the status bar by changing this value to correlate with the + drawable's defined in a LevelListDrawable. See the {@link android.graphics.drawable.LevelListDrawable} + reference for more information.
    +
    + +

    See the {@link android.app.Notification} class reference for more information about additional +features that you can customize for your application.

    + + +

    Creating a Custom Expanded View

    + + + +

    By default, the expanded view used in the "Notifications" window includes a basic title and text +message. These are defined by the contentTitle and contentText +parameters of the {@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) +setLatestEventInfo()} method. However, you can also define a custom layout for the expanded view using +{@link android.widget.RemoteViews}. The screenshot to the right shows an example of a +custom expanded view that uses an ImageView and TextView in a LinearLayout.

    + +

    To define your own layout for the expanded message, +instantiate a {@link android.widget.RemoteViews} object and +pass it to the contentView field of your Notification. Pass the +{@link android.app.PendingIntent} to the contentIntent field.

    + +

    Creating a custom expanded view is best understood with an example:

    + +
      +
    1. Create the XML layout for the expanded view. + For example, create a layout file called custom_notification_layout.xml and + build it like so: +
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +              android:orientation="horizontal"
      +              android:layout_width="fill_parent"
      +              android:layout_height="fill_parent"
      +              android:padding="3dp"
      +              >
      +    <ImageView android:id="@+id/image"
      +              android:layout_width="wrap_content"
      +              android:layout_height="fill_parent"
      +              android:layout_marginRight="10dp"
      +              />
      +    <TextView android:id="@+id/text"
      +              android:layout_width="wrap_content"
      +              android:layout_height="fill_parent"
      +              android:textColor="#000"
      +              />
      +</LinearLayout>
      +
      + +

      This layout is used for the expanded view, + but the content of the ImageView and TextView still needs to be defined by the applicaiton. + RemoteViews offers some convenient methods that allow you to define this content...

      +
    2. + +
    3. In the application code, use the RemoveViews + methods to define the image and text. Then pass the RemoteViews object to the contentView + field of the Notification, as shown in this example: +
      +RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);
      +contentView.setImageViewResource(R.id.image, R.drawable.notification_image);
      +contentView.setTextViewText(R.id.text, "Hello, this message is in a custom expanded view");
      +notification.contentView = contentView;
      +
      + +

      As shown here, pass the applicaiton's package name and the layout + resource ID to the RemoteViews constructor. Then, define the content for the ImageView and TextView, + using the {@link android.widget.RemoteViews#setImageViewResource(int, int) setImageViewResource()} + and {@link android.widget.RemoteViews#setTextViewText(int, CharSequence) setTextViewText()}. + In each case, pass the reference ID of the appropriate View object that you want to set, along with + the value for that View. Finally, the RemoteViews object is passed to the Notification in the + contentView field.

      +
    4. + +
    5. Because you don't need the + {@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) + setLatestEventInfo()} method when using a custom view, you must define the Intent for the Notification + with the contentIntent field, as in this example: +
      +Intent notificationIntent = new Intent(this, MyClass.class);
      +PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
      +notification.contentIntent = contentIntent;
      +
      +
    6. + +
    7. The notification can now be sent as usual: +
      mNotificationManager.notify(CUSTOM_VIEW_ID, notification);
      +
    8. +
    + + +

    The RemoteViews class also includes methods that you can use to easily add a +{@link android.widget.Chronometer} or {@link android.widget.ProgressBar} +in your notification's expanded view. For more information about creating custom layouts with +RemoteViews, refer to the {@link android.widget.RemoteViews} class reference.

    + +

    Note: +When creating a custom expanded view, you must take special care to ensure that your +custom layout functions properly in different device orientations and resolutions. While this +advice applies to all View layouts created on Android, it is especially important in this case +because your layout real estate is very restricted. So don't make your custom layout too +complex and be sure to test it in various configurations.

    + + + + diff --git a/docs/html/guide/topics/ui/notifiers/toasts.jd b/docs/html/guide/topics/ui/notifiers/toasts.jd new file mode 100644 index 0000000000000000000000000000000000000000..a800c3c900dfd8a7a317b0aadc76871a75ed7f6b --- /dev/null +++ b/docs/html/guide/topics/ui/notifiers/toasts.jd @@ -0,0 +1,154 @@ +page.title=Creating Toast Notifications +parent.title=Notifying the User +parent.link=index.html +@jd:body + +
    +
    +

    Key classes

    +
      +
    1. {@link android.widget.Toast}
    2. +
    +

    In this document

    +
      +
    1. The Basics
    2. +
    3. Positioning your Toast
    4. +
    5. Creating a Custom Toast View
    6. +
    +
    +
    + +

    A toast notificaiton is a message that pops up on the surface of the window. +It only fills the amount of space required for the message and the user's current +activity remains visible and interactive. The notification automatically fades in and +out, and does not accept interaction events.

    + +

    The screenshot below shows an example toast notification from the Alarm application. +Once an alarm is turned on, a toast is displayed to assure you that the +alarm was set.

    + + +

    A toast can be created and displayed from an {@link android.app.Activity} or +{@link android.app.Service}. If you create a toast notification from a Service, it +appears in front of the Activity currently in focus.

    + +

    If user response to the notification is required, consider using a +Status Bar Notification.

    + + +

    The Basics

    + +

    First, instantiate a {@link android.widget.Toast} +object with one of the {@link android.widget.Toast#makeText(Context,int,int) makeText()} methods. +This method takes three parameters: the application {@link android.content.Context}, +the text message, and the duration for the toast. It returns a properly initialized Toast +object. You can display the toast notification with {@link android.widget.Toast#show()}, +as shown in the following example:

    + +
    +Context context = getApplicationContext();
    +CharSequence text = "Hello toast!";
    +int duration = Toast.LENGTH_SHORT;
    +
    +Toast toast = Toast.makeText(context, text, duration);
    +toast.show();
    +
    + +

    This example demonstrates everything you need for most toast notifications. +You should rarely need anything else. You may, however, want to position the +toast differently or even use your own layout instead of a simple text message. +The following sections describe how you can do these things.

    + +

    You can also chain your methods and avoid holding on to the Toast object, like this:

    +
    Toast.makeText(context, text, duration).show();
    + + +

    Positioning your Toast

    + +

    A standard toast notification appears near the bottom of the screen, centered horizontally. +You can change this position with the {@link android.widget.Toast#setGravity(int,int,int)} +method. This accepts three parameters: a {@link android.view.Gravity} constant, +an x-position offset, and a y-position offset.

    + +

    For example, if you decide that the toast should appear in the top-left corner, you can set the +gravity like this:

    +
    +toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);
    +
    + +

    If you want to nudge the position to the right, increase the value of the second parameter. +To nudge it down, increase the value of the last parameter. + + +

    Creating a Custom Toast View

    + + + +

    If a simple text message isn't enough, you can create a customized layout for your +toast notification. To create a custom layout, define a View layout, +in XML or in your application code, and pass the root {@link android.view.View} object +to the {@link android.widget.Toast#setView(View)} method.

    + +

    For example, you can create the layout for the toast visible in the screenshot to the right +with the following XML (saved as toast_layout.xml):

    +
    +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    +              android:id="@+id/toast_layout_root"
    +              android:orientation="horizontal"
    +              android:layout_width="fill_parent"
    +              android:layout_height="fill_parent"
    +              android:padding="10dp"
    +              android:background="#DAAA"
    +              >
    +    <ImageView android:id="@+id/image"
    +               android:layout_width="wrap_content"
    +               android:layout_height="fill_parent"
    +               android:layout_marginRight="10dp"
    +               />
    +    <TextView android:id="@+id/text"
    +              android:layout_width="wrap_content"
    +              android:layout_height="fill_parent"
    +              android:textColor="#FFF"
    +              />
    +</LinearLayout>
    +
    + +

    Notice that the ID of the LinearLayout element is "toast_layout". You must use this +ID to inflate the layout from the XML, as shown here:

    + +
    +LayoutInflater inflater = getLayoutInflater();
    +View layout = inflater.inflate(R.layout.toast_layout,
    +                               (ViewGroup) findViewById(R.id.toast_layout_root));
    +
    +ImageView image = (ImageView) layout.findViewById(R.id.image);
    +image.setImageResource(R.drawable.android);
    +TextView text = (TextView) layout.findViewById(R.id.text);
    +text.setText("Hello! This is a custom toast!");
    +
    +Toast toast = new Toast(getApplicationContext());
    +toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
    +toast.setDuration(Toast.LENGTH_LONG);
    +toast.setView(layout);
    +toast.show();
    +
    + +

    First, retrieve the {@link android.view.LayoutInflater} with +{@link android.app.Activity#getLayoutInflater()} +(or {@link android.content.Context#getSystemService(String) getSystemService()}), +and then inflate the layout from XML using +{@link android.view.LayoutInflater#inflate(int, ViewGroup)}. The first parameter +is the layout resource ID and the second is the root View. You can use +this inflated layout to find more View objects in the layout, so now capture and +define the content for the ImageView and TextView elements. Finally, create +a new Toast with {@link android.widget.Toast#Toast(Context)} and set some properties +of the toast, such as the gravity and duration. Then call +{@link android.widget.Toast#setView(View)} and pass it the inflated layout. +You can now display the toast with your custom layout by calling +{@link android.widget.Toast#show()}.

    + +

    Note: Do not use the public constructor for a Toast +unless you are going to define the layout with {@link android.widget.Toast#setView(View)}. +If you do not have a custom layout to use, you must use +{@link android.widget.Toast#makeText(Context,int,int)} to create the Toast.

    + diff --git a/docs/html/guide/tutorials/hello-world.jd b/docs/html/guide/tutorials/hello-world.jd index f277b10fd552ada33e216826f9d95a49702ea7ab..4d1e9cdf5b6752ea4d992453020f5ceb707f09e1 100644 --- a/docs/html/guide/tutorials/hello-world.jd +++ b/docs/html/guide/tutorials/hello-world.jd @@ -1,6 +1,21 @@ page.title=Hello, World @jd:body + +

    As a developer, you know that the first impression of a development framework is how easy it is to write "Hello, World." Well, on Android, it's pretty easy. @@ -19,56 +34,63 @@ here when you've completed the installation.

    Create an AVD

    -

    Note: If you're developing with an Android SDK older -than the one provided for Android 1.5, you can skip this step and continue with -Create the Project.

    + -

    In this tutorial, you will run your applicion in the Android Emulator. +

    In this tutorial, you will run your application in the Android Emulator. Before you can launch the emulator, you must create an Android Virtual Device (AVD). An AVD defines the system image and device settings used by the emulator.

    -

    To create an AVD, use the android tool provided in the Android SDK. +

    To create an AVD, use the "android" tool provided in the Android SDK. Open a command prompt or terminal, navigate to the -/tools directory in the SDK package and execute: +tools/ directory in the SDK package and execute:

    -android create avd --target 1 --name myavd
    +android create avd --target 2 --name my_avd
     
    -

    The tool now asks if you would like to create a custom hardware profile, say -no. That's it. You now have an AVD and can use it to run the Emulator.

    +

    The tool now asks if you would like to create a custom hardware profile. +For the time being, press Return to skip it ("no" is the default response). +That's it. This configures an AVD named "my_avd" that uses the Android 1.5 +platform. The AVD is now ready for use in the emulator.

    + +

    In the above command, the --target option is required +and specifies the deployment target to run on the emulator. +The --name option is also required and defines the +name for the new AVD.

    -

    In the above command, the target option is required -and specifies the target platform for the emulator. (A target defines the system image, -API level and supported skins. To view all available targets, execute: -android list target.) The name option is also required -and defines the name for the new AVD. For more information about android, -see the Android Tool -documentation.

    -

    Create the Project

    +

    Create a New Android Project

    + +

    After you've created an AVD, the next step is to start a new +Android project in Eclipse.

      -
    1. Open a new Android Project. -

      From Eclipse, select the File > New > Project menu item. If the Android - Plugin for Eclipse has been successfully installed, the resulting dialog - should have a folder labeled "Android" which should contain a single entry: - "Android Project". (After you create one or more Android projects, an entry for - "Android XML File" will also be available.)

      -

      Selected "Android Project" and click Next.

      - - +
    2. From Eclipse, select File > New > Project. +

      If the ADT + Plugin for Eclipse has been successfully installed, the resulting dialog + should have a folder labeled "Android" which should contain + "Android Project". (After you create one or more Android projects, an entry for + "Android XML File" will also be available.)

      +
    3. +
    4. Selected "Android Project" and click Next. +
    5. -
    6. Fill out the project details. -

      The next screen allows you to enter the relevant details for your project:

      +
    7. Fill in the project details with the following values:
      • Project name: HelloAndroid
      • Application name: Hello, Android
      • Package name: com.example.helloandroid (or your own private namespace)
      • Create Activity: HelloAndroid
      • -
      • Min SDK Version: 3
      • +
      • Min SDK Version: 2

      Click Finish.

      @@ -102,25 +124,34 @@ documentation.

      chooses, but it doesn't need to. As the checkbox suggests, this is optional, but an Activity is almost always used as the basis for an application.
      Min SDK Version
      -
      This value specifies the API Level required by your application. With each new +
      This value specifies the minimum API Level required by your application. If the API Level + entered here matches the API Level provided by one of the available targets, + then that Build Target will be automatically selected (in this case, entering + "2" as the API Level will select the Android 1.1 target). With each new version of the Android system image and Android SDK, there have likely been additions or changes made to the APIs. When this occurs, a new API Level is assigned to the system image to regulate which applications are allowed to be run. If an - application requires an API Level that is higher than the level supported by the device, - then the application is not allowed to be installed. Because the "Hello World" - application uses APIs that have not changed since the first release, you can safely - declare API Level "1" for the Min SDK Version, which is supported by all Android - devices.
      + application requires an API Level that is higher than the level supported + by the device, then the application will not be installed.

      Other fields: The checkbox for "Use default location" allows you to change - the location on disk where the project's files will be generated and stored. "Target" - is the platform target for your application.

      - + the location on disk where the project's files will be generated and stored. "Build Target" + is the platform target that your application will be compiled against + (this should be selected automatically, based on your Min SDK Version).

      + +

      Notice that the "Build Target" you've selected uses the Android 1.1 + platform. This means that your application will be compiled against the Android 1.1 + platform library. If you recall, the AVD created above runs on the Android 1.5 platform. + These don't have to match; Android applications are forward-compatible, so an application + built against the 1.1 platform library will run normally on the 1.5 platform. The reverse + is not true.

    8. + -
    9. View the generated Activity. -

      Open the HelloAndroid.java file, located inside HelloAndroid > src > +

      Your Android project is now ready. It should be visible in the Package +Explorer on the left. +Open the HelloAndroid.java file, located inside HelloAndroid > src > com.example.helloandroid). It should look like this:

      @@ -147,8 +178,6 @@ it is where you should perform all initialization and UI setup. An activity is n
       have a user interface, but usually will.

      Now let's modify some code!

      -
    10. -

    Construct the UI

    @@ -191,10 +220,10 @@ on. The Activity class inherits from Context, and because your HelloAndroid class is a subclass of Activity, it is also a Context. So, you can pass this as your Context reference to the TextView.

    -

    Next, define the text content with +

    Next, you define the text content with {@link android.widget.TextView setText(CharSequence) setText()}.

    -

    Finally, pass the TextView to +

    Finally, you pass the TextView to {@link android.app.Activity#setContentView(View) setContentView()} in order to display it as the content for the Activity UI. If your Activity doesn't call this method, then no UI is present and the system will display a blank @@ -204,42 +233,39 @@ screen.

    to see it running.

    -

    Run the Code

    +

    Run the Application

    -

    The Eclipse plugin makes it very easy to run your applications. -Select Run > Run Configurations (in Eclipse 3.3, -Run > Open Run Dialog).

    +

    The Eclipse plugin makes it very easy to run your applications:

    -

    Select the "Android Application" entry, and click the icon in the -top left corner (the one depicting a sheet of paper with a plus symbol) -or double-click on "Android Application." You should -have a new launcher entry named "New_configuration".

    - - +
      +
    1. Select Run > Run.
    2. +
    3. Select "Android Application".
    4. +
    -

    Change the name to something meaningful like "Android Activity." Then pick -click the Browse button and select your HelloAndroid project. The -plugin will automatically scan your project for Activity subclasses and add -each one it finds to the drop-down list under "Launch Action." Because the -HelloAndroid project only has one Activity, it will be the default Activity. -Leave "Launch Default Activity" selected.

    + -

    Click the Apply, then Run. The Android Emulator -will start and once it's booted up your application will appear. You should now -see something like this:

    +

    The Eclipse ADT will automatically create a new run configuration for your project +and the Android Emulator will automatically launch. Once the emulator is booted up, +your application will appear after a moment. You should now see something like this:

    The "Hello, Android" you see in the grey bar is actually the application title. The Eclipse plugin -creates this automatically (the string is defined in the /res/values/strings.xml file and referenced -by your AndroidManifest.xml file). The text below the title is the actual text that you have +creates this automatically (the string is defined in the res/values/strings.xml file and referenced +by your AndroidManifest.xml file). The text below the title is the actual text that you have created in the TextView object.

    -

    That covers the basic "Hello World" tutorial, but you should continue reading for some more +

    That concludes the basic "Hello World" tutorial, but you should continue reading for some more valuable information about developing Android applications.

    -

    Upgrading the UI to an XML Layout

    +

    Upgrade the UI to an XML Layout

    The "Hello, World" example you just completed uses what is called a "programmatic" UI layout. This means that you constructed and built your application's UI @@ -326,7 +352,7 @@ In this case, it's the only View so you want it to take up the entire screen, wh -

    These XML layout files belong in the res/layout/ directory of your project. The "res" is +

    These XML layout files belong in the res/layout/ directory of your project. The "res" is short for "resources" and the directory contains all the non-code assets that your application requires. In addition to layout files, resources also include assets such as images, sounds, and localized strings.

    @@ -348,7 +374,7 @@ existing application to use an XML layout.

    1. In the Eclipse Package Explorer, expand the -/res/layout/ folder and open main.xml (once opened, you might need to click +/res/layout/ folder and open main.xml (once opened, you might need to click the "main.xml" tab at the bottom of the window to see the XML source). Replace the contents with the following XML: @@ -360,7 +386,7 @@ the following XML:

      Save the file.

    2. -
    3. Inside the /res/values folder, open strings.xml. +
    4. Inside the res/values/ folder, open strings.xml. This is where you should save all default text strings for your user interface. If you're using Eclipse, then ADT will have started you with two strings, hello and app_name. Revise hello to something else. Perhaps "Hello, Android! I am a string resource!" @@ -398,7 +424,7 @@ suggestions. You'll find that it helps in a lot of situations.

      Instead of passing setContentView() a View object, you give it a reference to the layout resource. The resource is identified as R.layout.main, which is actually a compiled object representation of -the layout defined in /res/layout/main.xml. The Eclipse plugin automatically creates this reference for +the layout defined in /res/layout/main.xml. The Eclipse plugin automatically creates this reference for you inside the project's R.java class. If you're not using Eclipse, then the R.java class will be generated for you when you run Ant to build the application. (More about the R class in a moment.)

    5. @@ -423,7 +449,7 @@ introduction page for an overview of the Dev Guide documentation.

      R class

      -

      In Eclipse, open the file named R.java (in the /gen [Generated Java Files] folder). +

      In Eclipse, open the file named R.java (in the gen/ [Generated Java Files] folder). It should look something like this:

      @@ -445,7 +471,7 @@ public final class R {
       }
       
      -

      A project's R.java file is an index into all the resources defined in the +

      A project's R.java file is an index into all the resources defined in the file. You use this class in your source code as a sort of short-hand way to refer to resources you've included in your project. This is particularly powerful with the code-completion features of IDEs like Eclipse @@ -456,13 +482,13 @@ you're looking for.

      For now, notice the inner class named "layout", and its member field "main". The Eclipse plugin noticed the XML layout file named main.xml and generated a class for it here. As you add other -resources to your project (such as strings in the res/values/string.xml file or drawables inside -the res/drawable/ direcory) you'll see R.java change to keep up.

      +resources to your project (such as strings in the res/values/string.xml file or drawables inside +the res/drawable/ direcory) you'll see R.java change to keep up.

      When not using Eclipse, this class file will be generated for you at build time (with the Ant tool).

      You should never edit this file by hand.

      -

      Debugging Your Project

      +

      Debug Your Project

      The Android Plugin for Eclipse also has excellent integration with the Eclipse debugger. To demonstrate this, introduce a bug into @@ -515,9 +541,9 @@ just as you would for any other application.

      Thus, it's possible to wrap those tools with another tool, such as an 'ant' build file.

      -

      The Android SDK includes a toolk named "android" that can be +

      The Android SDK includes a tool named "android" that can be used to create all the source code and directory stubs for your project, as well - as an ant-compatible build.xml file. This allows you to build your project + as an ant-compatible build.xml file. This allows you to build your project from the command line, or integrate it with the IDE of your choice.

      For example, to create a HelloAndroid project similar to the one created @@ -527,18 +553,12 @@ just as you would for any other application.

      android create project \ --package com.android.helloandroid \ --activity HelloAndroid \ - --target 1 \ - --path <path-for-your-project>/HelloAndroid \ - --mode activity + --target 2 \ + --path <path-to-your-project>/HelloAndroid

      This creates the required folders and files for the project at the location defined by the path.

      -

      To build the project, you'd then run the command ant. When that command - successfully completes, you'll be left with a file named HelloAndroid.apk under - the "bi"' directory. That .apk file is an Android Package, and can be - installed and run in your emulator using the 'adb' tool.

      - -

      For more information on how to use these tools, please read +

      For more information on how to use the SDK tools to create and build projects, please read Developing in Other IDEs.

      diff --git a/docs/html/guide/tutorials/images/hello_world_1.png b/docs/html/guide/tutorials/images/hello_world_1.png index 02682f45152d3ced57e2aec737c49f87243c0a6d..1e5f7b0cdfe3a84432e940d897b4fbd000d24026 100644 Binary files a/docs/html/guide/tutorials/images/hello_world_1.png and b/docs/html/guide/tutorials/images/hello_world_1.png differ diff --git a/docs/html/guide/tutorials/images/hello_world_9.png b/docs/html/guide/tutorials/images/hello_world_9.png index e172e639a0fb9b7a94080b9edc4f7e790b6368d4..a66526ad6ca22265fb1dcdeca14d941f5bb51a6d 100644 Binary files a/docs/html/guide/tutorials/images/hello_world_9.png and b/docs/html/guide/tutorials/images/hello_world_9.png differ diff --git a/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip b/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip index c7dd989f2eba8b8591c8c521addf89c10d3ba1e3..24fefc1a31fba645c4f066b31a00ddcdda7c505d 100644 Binary files a/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip and b/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip differ diff --git a/docs/html/guide/tutorials/notepad/notepad-ex1.jd b/docs/html/guide/tutorials/notepad/notepad-ex1.jd index b7f42bf095839eeda7ee68a22dbe553961a52818..b5173b8244405b5ec2a5ed9e56adf9258f57dae3 100644 --- a/docs/html/guide/tutorials/notepad/notepad-ex1.jd +++ b/docs/html/guide/tutorials/notepad/notepad-ex1.jd @@ -44,11 +44,13 @@ selections.
      In the New Android Project dialog, select Create project from existing source.
    6. Click Browse and navigate to where you copied the NotepadCodeLab - (downloaded during setup). Select - Notepadv1 and click Choose.
    7. + (downloaded during setup) + and select Notepadv1.
    8. - You should see Notepadv1 in the Project name and also see the Location - filled in with the path you selected.
    9. + The Project Name and other properties should be automatically filled for you. + You must select the Build Target—we recommend selecting a target with the + lowest platform version available. Also add an integer to the Min SDK Version field + that matches the API Level of the selected Build Target.
    10. Click Finish. The Notepadv1 project should open and be visible in your Eclipse package explorer.
    11. diff --git a/docs/html/guide/tutorials/views/hello-mapview.jd b/docs/html/guide/tutorials/views/hello-mapview.jd index 976b8ab42e500db582275f19ab9c6e43ba2e38cd..868bfaa6a081d21885cc801e7a031fd56d3779db 100644 --- a/docs/html/guide/tutorials/views/hello-mapview.jd +++ b/docs/html/guide/tutorials/views/hello-mapview.jd @@ -3,6 +3,32 @@ parent.title=Hello, Views parent.link=index.html @jd:body +
      +

      This tutorial requires that you have the Google Maps external library +installed in your SDK environment. By default the Android 1.5 SDK includes the +Google APIs add-on, which in turn includes the Maps external library. If you +don't have the Google APIs SDK add-on, you can download it from this +location:

      + +

      http://code.google.com/android/add-ons/google-apis

      + +

      The Google APIs add-on requires Android 1.5 SDK or later release. After +installing the add-on in your SDK, set your project properties to use the build +target called "Google APIs Add-on". See the instructions for setting a build +target in Developing in +Eclipse with ADT or Developing in Other IDEs, +as appropriate for your environment.

      + +

      You will also need to use the android tool to set up an AVD that uses the +Google APIs deployment target. See Android Virtual Devices for +more information. Once you have set up your environment, you will be able to +build and run the project described in this tutorial

      + +
      +

      A MapView allows you to create your own map-viewing Activity. First, we'll create a simple Activity that can view and navigate a map. Then we will add some overlay items.

      @@ -49,7 +75,7 @@ First, we'll create a simple Activity that can view and navigate a map. Then we certificate has been registered with the Google Maps service. Because MapView uses Google Maps data, this key is required in order to receive the map data, even while you are developing. Registration is free and it only takes a couple minutes to register your certificate and receive a Maps API Key. For instructions on getting a key, read - Obtaining a Maps API Key. + Obtaining a Maps API Key. (For the purpose of this tutorial, you should register with the fingerprint of the SDK debug certificate.) Once you've acquired the Maps API Key, insert it for the apiKey value.

      diff --git a/docs/html/images/appwidget.png b/docs/html/images/appwidget.png new file mode 100644 index 0000000000000000000000000000000000000000..b72b80b1d332b305b9ef56ca88b40f82c15459bb Binary files /dev/null and b/docs/html/images/appwidget.png differ diff --git a/docs/html/images/custom_message.png b/docs/html/images/custom_message.png new file mode 100755 index 0000000000000000000000000000000000000000..ea7c7160e020ce0436aac94c3c950542201f6f3b Binary files /dev/null and b/docs/html/images/custom_message.png differ diff --git a/docs/html/images/custom_toast.png b/docs/html/images/custom_toast.png new file mode 100755 index 0000000000000000000000000000000000000000..230625a850053e0f8da4608873f610259a251078 Binary files /dev/null and b/docs/html/images/custom_toast.png differ diff --git a/docs/html/images/dialog_buttons.png b/docs/html/images/dialog_buttons.png new file mode 100755 index 0000000000000000000000000000000000000000..81aaec4a6ce5a1be77f29a10d09eacea938b1fde Binary files /dev/null and b/docs/html/images/dialog_buttons.png differ diff --git a/docs/html/images/dialog_custom.png b/docs/html/images/dialog_custom.png new file mode 100755 index 0000000000000000000000000000000000000000..b2523fd5c8922c5a4562adc7e6ebf05a6acda21d Binary files /dev/null and b/docs/html/images/dialog_custom.png differ diff --git a/docs/html/images/dialog_list.png b/docs/html/images/dialog_list.png new file mode 100755 index 0000000000000000000000000000000000000000..f2736bf4218dfdb39b5edbe7bf8d0ac068b182a8 Binary files /dev/null and b/docs/html/images/dialog_list.png differ diff --git a/docs/html/images/dialog_progress_bar.png b/docs/html/images/dialog_progress_bar.png new file mode 100755 index 0000000000000000000000000000000000000000..3e74419f8976b5aedcbde75b5d17d264e8ec1fd7 Binary files /dev/null and b/docs/html/images/dialog_progress_bar.png differ diff --git a/docs/html/images/dialog_progress_spinning.png b/docs/html/images/dialog_progress_spinning.png new file mode 100755 index 0000000000000000000000000000000000000000..501f48026637fac99c4cc0b322547e0b2449910f Binary files /dev/null and b/docs/html/images/dialog_progress_spinning.png differ diff --git a/docs/html/images/dialog_singlechoicelist.png b/docs/html/images/dialog_singlechoicelist.png new file mode 100755 index 0000000000000000000000000000000000000000..90629f0f18f8f8770efd06f030e867f820807ffa Binary files /dev/null and b/docs/html/images/dialog_singlechoicelist.png differ diff --git a/docs/html/images/jet/clip_marker.png b/docs/html/images/jet/clip_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..70760c0582e5202d93bf1c7ad792676b8d689e3c Binary files /dev/null and b/docs/html/images/jet/clip_marker.png differ diff --git a/docs/html/images/jet/event_marker.png b/docs/html/images/jet/event_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..9cd72d214337bf81e625c07b77af887608e47388 Binary files /dev/null and b/docs/html/images/jet/event_marker.png differ diff --git a/docs/html/images/jet/jc_audition_wnd.png b/docs/html/images/jet/jc_audition_wnd.png new file mode 100755 index 0000000000000000000000000000000000000000..43f0fb1043afb4df5b6bc3774e228f793e3adfd6 Binary files /dev/null and b/docs/html/images/jet/jc_audition_wnd.png differ diff --git a/docs/html/images/jet/jc_event_wnd.png b/docs/html/images/jet/jc_event_wnd.png new file mode 100755 index 0000000000000000000000000000000000000000..807797e871b907f6c31a214480f8950d7dd55b5e Binary files /dev/null and b/docs/html/images/jet/jc_event_wnd.png differ diff --git a/docs/html/images/jet/jc_main_wnd.png b/docs/html/images/jet/jc_main_wnd.png new file mode 100755 index 0000000000000000000000000000000000000000..29c47ec0c09ce06fc358b1e394b20e77096f96a6 Binary files /dev/null and b/docs/html/images/jet/jc_main_wnd.png differ diff --git a/docs/html/images/jet/jc_moveseg_wnd.png b/docs/html/images/jet/jc_moveseg_wnd.png new file mode 100755 index 0000000000000000000000000000000000000000..690dcadeb10fefdb02c93ac74d7eeaaa0acb5b9c Binary files /dev/null and b/docs/html/images/jet/jc_moveseg_wnd.png differ diff --git a/docs/html/images/jet/jc_open_dlg.png b/docs/html/images/jet/jc_open_dlg.png new file mode 100755 index 0000000000000000000000000000000000000000..0d5a14d230b1e8d5a948d1c4c7238ab8637805a6 Binary files /dev/null and b/docs/html/images/jet/jc_open_dlg.png differ diff --git a/docs/html/images/jet/jc_rep_wnd.png b/docs/html/images/jet/jc_rep_wnd.png new file mode 100755 index 0000000000000000000000000000000000000000..ca200d1cbcf41fcd97cece05e060b39617fcb776 Binary files /dev/null and b/docs/html/images/jet/jc_rep_wnd.png differ diff --git a/docs/html/images/jet/jc_repseg_wnd.png b/docs/html/images/jet/jc_repseg_wnd.png new file mode 100755 index 0000000000000000000000000000000000000000..786790213486033c5c129e1c7b0cd71f00cc6d0f Binary files /dev/null and b/docs/html/images/jet/jc_repseg_wnd.png differ diff --git a/docs/html/images/jet/jc_seg_wnd.png b/docs/html/images/jet/jc_seg_wnd.png new file mode 100755 index 0000000000000000000000000000000000000000..b0434d778d9be401cb1f533dfd717fb132ce65cc Binary files /dev/null and b/docs/html/images/jet/jc_seg_wnd.png differ diff --git a/docs/html/images/jet/linear_music.png b/docs/html/images/jet/linear_music.png new file mode 100644 index 0000000000000000000000000000000000000000..d51fc23f77b3a1c2b6309183c18270a9f0c17ccc Binary files /dev/null and b/docs/html/images/jet/linear_music.png differ diff --git a/docs/html/images/jet/music_game.png b/docs/html/images/jet/music_game.png new file mode 100644 index 0000000000000000000000000000000000000000..4225794f7b1f05920752dd0b6479d6cb4339b00a Binary files /dev/null and b/docs/html/images/jet/music_game.png differ diff --git a/docs/html/images/jet/nonlinear_music.png b/docs/html/images/jet/nonlinear_music.png new file mode 100644 index 0000000000000000000000000000000000000000..99d7775ae5bc820723011ddc3b06a404ab0368a6 Binary files /dev/null and b/docs/html/images/jet/nonlinear_music.png differ diff --git a/docs/html/images/jet/sync_muteunmute.png b/docs/html/images/jet/sync_muteunmute.png new file mode 100644 index 0000000000000000000000000000000000000000..1238c4e2173b5249dec937ec292124e940f5a661 Binary files /dev/null and b/docs/html/images/jet/sync_muteunmute.png differ diff --git a/docs/html/images/notifications_window.png b/docs/html/images/notifications_window.png new file mode 100755 index 0000000000000000000000000000000000000000..78e0c8a52f238e31106c30a940b0f246be200a1b Binary files /dev/null and b/docs/html/images/notifications_window.png differ diff --git a/docs/html/images/status_bar.png b/docs/html/images/status_bar.png new file mode 100755 index 0000000000000000000000000000000000000000..420bb03be861f29345a39fbf7f9f525e260b7aa8 Binary files /dev/null and b/docs/html/images/status_bar.png differ diff --git a/docs/html/images/toast.png b/docs/html/images/toast.png new file mode 100644 index 0000000000000000000000000000000000000000..223048a396143812e5e332264e20dd9c8ced72e2 Binary files /dev/null and b/docs/html/images/toast.png differ diff --git a/docs/html/images/widget_design/2x2_Widget_Frame_Landscape.png b/docs/html/images/widget_design/2x2_Widget_Frame_Landscape.png new file mode 100644 index 0000000000000000000000000000000000000000..a73a09a61f8d27570214f23d8a00fa324f4453a0 Binary files /dev/null and b/docs/html/images/widget_design/2x2_Widget_Frame_Landscape.png differ diff --git a/docs/html/images/widget_design/2x2_Widget_Frame_Landscape.psd b/docs/html/images/widget_design/2x2_Widget_Frame_Landscape.psd new file mode 100644 index 0000000000000000000000000000000000000000..cd869b5861f37d09f8a7abcf345f77b5486cfa91 Binary files /dev/null and b/docs/html/images/widget_design/2x2_Widget_Frame_Landscape.psd differ diff --git a/docs/html/images/widget_design/2x2_Widget_Frame_Portrait.png b/docs/html/images/widget_design/2x2_Widget_Frame_Portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..95ac03118c4220778cca032de1f8f6db173154ec Binary files /dev/null and b/docs/html/images/widget_design/2x2_Widget_Frame_Portrait.png differ diff --git a/docs/html/images/widget_design/2x2_Widget_Frame_Portrait.psd b/docs/html/images/widget_design/2x2_Widget_Frame_Portrait.psd new file mode 100644 index 0000000000000000000000000000000000000000..9f0a7b0cf3af62fc54d2c08c5a2f36529da93ad7 Binary files /dev/null and b/docs/html/images/widget_design/2x2_Widget_Frame_Portrait.psd differ diff --git a/docs/html/images/widget_design/3x3_Widget_Frame_Landscape.png b/docs/html/images/widget_design/3x3_Widget_Frame_Landscape.png new file mode 100644 index 0000000000000000000000000000000000000000..14013dc0973d2c5ebc3a80dfcb1f589b9440f00a Binary files /dev/null and b/docs/html/images/widget_design/3x3_Widget_Frame_Landscape.png differ diff --git a/docs/html/images/widget_design/3x3_Widget_Frame_Landscape.psd b/docs/html/images/widget_design/3x3_Widget_Frame_Landscape.psd new file mode 100644 index 0000000000000000000000000000000000000000..50a2b8ca0808e5ce296a58e4dfb3d17dec3cd99a Binary files /dev/null and b/docs/html/images/widget_design/3x3_Widget_Frame_Landscape.psd differ diff --git a/docs/html/images/widget_design/3x3_Widget_Frame_Portrait.png b/docs/html/images/widget_design/3x3_Widget_Frame_Portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..22f99f8631b0ac0d28339523c8ee49901f00fd18 Binary files /dev/null and b/docs/html/images/widget_design/3x3_Widget_Frame_Portrait.png differ diff --git a/docs/html/images/widget_design/3x3_Widget_Frame_Portrait.psd b/docs/html/images/widget_design/3x3_Widget_Frame_Portrait.psd new file mode 100644 index 0000000000000000000000000000000000000000..591e963d6e02e0dcc8cf3a8d20b7e19e421331bd Binary files /dev/null and b/docs/html/images/widget_design/3x3_Widget_Frame_Portrait.psd differ diff --git a/docs/html/images/widget_design/4x1_Widget_Frame_Landscape.png b/docs/html/images/widget_design/4x1_Widget_Frame_Landscape.png new file mode 100644 index 0000000000000000000000000000000000000000..c6a3f7adea71a66fb7d3bfbcf086180771a63ae9 Binary files /dev/null and b/docs/html/images/widget_design/4x1_Widget_Frame_Landscape.png differ diff --git a/docs/html/images/widget_design/4x1_Widget_Frame_Landscape.psd b/docs/html/images/widget_design/4x1_Widget_Frame_Landscape.psd new file mode 100644 index 0000000000000000000000000000000000000000..ec811798ba051881f296c76b637b4d8204fd5a38 Binary files /dev/null and b/docs/html/images/widget_design/4x1_Widget_Frame_Landscape.psd differ diff --git a/docs/html/images/widget_design/4x1_Widget_Frame_Portrait.png b/docs/html/images/widget_design/4x1_Widget_Frame_Portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc8665cdb6758f2785856b0d22324d2f4a633ff Binary files /dev/null and b/docs/html/images/widget_design/4x1_Widget_Frame_Portrait.png differ diff --git a/docs/html/images/widget_design/4x1_Widget_Frame_Portrait.psd b/docs/html/images/widget_design/4x1_Widget_Frame_Portrait.psd new file mode 100644 index 0000000000000000000000000000000000000000..bad7ad12681151ab7a0dd4bf9cfbb728e4e51690 Binary files /dev/null and b/docs/html/images/widget_design/4x1_Widget_Frame_Portrait.psd differ diff --git a/docs/html/images/widget_design/Add_Noise.png b/docs/html/images/widget_design/Add_Noise.png new file mode 100644 index 0000000000000000000000000000000000000000..c323bb490c3609fc582c9f5d5105be10324e950e Binary files /dev/null and b/docs/html/images/widget_design/Add_Noise.png differ diff --git a/docs/html/images/widget_design/Layer_Style.png b/docs/html/images/widget_design/Layer_Style.png new file mode 100644 index 0000000000000000000000000000000000000000..7577803142447b323e20d71b6217c3a8fa2c9457 Binary files /dev/null and b/docs/html/images/widget_design/Layer_Style.png differ diff --git a/docs/html/images/widget_design/Music_widget_button_states.psd b/docs/html/images/widget_design/Music_widget_button_states.psd new file mode 100644 index 0000000000000000000000000000000000000000..17f3573d509784586b0828555bc82669fade56b3 Binary files /dev/null and b/docs/html/images/widget_design/Music_widget_button_states.psd differ diff --git a/docs/html/images/widget_design/alignment.png b/docs/html/images/widget_design/alignment.png new file mode 100644 index 0000000000000000000000000000000000000000..2e794dde0ea0764ada1c588b7ffc9e87bfda604f Binary files /dev/null and b/docs/html/images/widget_design/alignment.png differ diff --git a/docs/html/images/widget_design/buttons.png b/docs/html/images/widget_design/buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d1df275f99701a12d120de5f4bd1924957b7fb Binary files /dev/null and b/docs/html/images/widget_design/buttons.png differ diff --git a/docs/html/images/widget_design/file_format.png b/docs/html/images/widget_design/file_format.png new file mode 100644 index 0000000000000000000000000000000000000000..26f0e562ab67bb5b3841fced9dfa43a2caf08b8f Binary files /dev/null and b/docs/html/images/widget_design/file_format.png differ diff --git a/docs/html/images/widget_design/landscape_sizes.png b/docs/html/images/widget_design/landscape_sizes.png new file mode 100644 index 0000000000000000000000000000000000000000..798bb159fd6685d0e575b815a596236ec7ee0926 Binary files /dev/null and b/docs/html/images/widget_design/landscape_sizes.png differ diff --git a/docs/html/images/widget_design/portrait_sizes.png b/docs/html/images/widget_design/portrait_sizes.png new file mode 100644 index 0000000000000000000000000000000000000000..9da252a4782cb8b06aecbeef7cb41a7a2caec9e1 Binary files /dev/null and b/docs/html/images/widget_design/portrait_sizes.png differ diff --git a/docs/html/images/widget_design/widget_examples.png b/docs/html/images/widget_design/widget_examples.png new file mode 100644 index 0000000000000000000000000000000000000000..e27ffbb24cfec51d5a8df6235847ec99b610e644 Binary files /dev/null and b/docs/html/images/widget_design/widget_examples.png differ diff --git a/docs/html/images/widget_design/widget_sizes_landscape.png b/docs/html/images/widget_design/widget_sizes_landscape.png new file mode 100644 index 0000000000000000000000000000000000000000..052e28e2492594ce6e9047fd80ddc23366c756e7 Binary files /dev/null and b/docs/html/images/widget_design/widget_sizes_landscape.png differ diff --git a/docs/html/images/widget_design/widget_sizes_portrait.png b/docs/html/images/widget_design/widget_sizes_portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..31a240c052c42b6e92c671b2e5858af30f5c7f1f Binary files /dev/null and b/docs/html/images/widget_design/widget_sizes_portrait.png differ diff --git a/docs/html/index.jd b/docs/html/index.jd index bd681e2c6d97774a8cbe6df4b119386018062218..883170a3aa87913ce7fdbab5f991cac2129c482a 100644 --- a/docs/html/index.jd +++ b/docs/html/index.jd @@ -12,7 +12,7 @@ home=true Google I/O Developer Conference 2009
      -

      Google I/O is a two-day developer event that will take place May 27-28 at Moscone Center, San Francisco.

      +

      Google I/O is a two-day developer event that will take place May 27-28 at Moscone Center, San Francisco. The agenda includes a number of great sessions on Android topics by team engineers and other developers.

      Learn more »

      @@ -43,7 +43,7 @@ home=true

      Download

      The Android SDK has the tools, sample code, and docs you need to create great apps.

      -

      Learn more »

      +

      Learn more »

      @@ -116,10 +116,10 @@ home=true 'sdk': { 'layout':"imgLeft", 'icon':"sdk-small.png", - 'name':"SDK 1.1 r1", + 'name':"SDK 1.5 r1", 'img':"sdk-large.png", - 'title':"Android 1.1 SDK r1", - 'desc': "

      A new Android SDK is available for download. The new SDK includes minor API changes, new UI localizations, bug fixes and some new application features.

      Download Android 1.1 SDK r1

      " + 'title':"Android 1.5 SDK r1", + 'desc': "

      The final version of the Android 1.5 SDK is now available. It includes new APIs for Android 1.5, updated developer tools, multiple platform versions, and a Google APIs add-on.

      Download Android 1.5 SDK

      " }, 'mapskey': { @@ -128,7 +128,7 @@ home=true 'name':"Maps API Key", 'img':"maps-large.png", 'title':"Maps API Key", - 'desc':"

      If you're writing an Android application that uses Google Maps (with MapView), you must register your application to obtain a Maps API Key. Without the key, your maps application will not work on Android devices. Obtaining a key requires just a couple of steps.

      Learn how to get a Maps API Key

      " + 'desc':"

      If you're writing an Android application that uses Google Maps (with MapView), you must register your application to obtain a Maps API Key. Without the key, your maps application will not work on Android devices. Obtaining a key requires just a couple of steps.

      Learn more »

      " }, 'market': { diff --git a/docs/html/maps-api-signup.html b/docs/html/maps-api-signup.html deleted file mode 100644 index a604b2ad0eb55d0d7122085b2aa13a529bf9adee..0000000000000000000000000000000000000000 --- a/docs/html/maps-api-signup.html +++ /dev/null @@ -1,369 +0,0 @@ - - - - - -Sign Up for the Android Maps API - Android Maps API - Google Code - - - - - - - - - - - -
      - - -
      - - -
      - - -
      - - -
      -

      Android Maps API Key Signup

      - -
      - - -
      - - - -
      -

      Sign Up for the Android Maps API

      - -

      The Android Maps API lets you embed -Google -Maps in your own Android applications. A single Maps API key is -valid for all applications signed by a single certificate. See -this documentation -page for more information about application signing. To get a -Maps API key for your certificate, you will need to provide its the certificate's -fingerprint. This can be obtained using Keytool. For example, on -Linux or Mac OSX, you would examine your debug keystore like this: -

      $ keytool -list -keystore ~/.android/debug.keystore
      -...
      -Certificate fingerprint (MD5): 94:1E:43:49:87:73:BB:E6:A6:88:D7:20:F1:8E:B5:98
      -
      - -

      If you use different keys for signing development builds and -release builds, you will need to obtain a separate Maps API key for -each certificate. Each key will only work in applications signed by -the corresponding certificate.

      - -

      You also need a Google Account -to get a Maps API key, and your API key will be connected to your Google Account.

      -
      -
      - -
      - -
      -
      - - - - - - - - - - - - - -
      I have read and agree with the terms and conditions (printable version)
      - My certificate's MD5 fingerprint: - -
      -
      -
      - - - - -
      -
      - -
      - - - - - diff --git a/docs/html/maps-api-tos.pdf b/docs/html/maps-api-tos.pdf deleted file mode 100644 index 80c28363a0215124ae663c9bfb2502b4fd04140c..0000000000000000000000000000000000000000 Binary files a/docs/html/maps-api-tos.pdf and /dev/null differ diff --git a/docs/html/offline.jd b/docs/html/offline.jd index d41459b4d64c7170363cb3cf068040466d318e60..a42e346ec4cdb629df14050950b85742952df1ac 100644 --- a/docs/html/offline.jd +++ b/docs/html/offline.jd @@ -9,16 +9,18 @@ page.title=Welcome

      If you've just downloaded the SDK, then continue with -Installing the Android SDK.

      +Installing the Android SDK.

      If you're upgrading from a previously installed version, then refer to the -Upgrading guide.

      +Upgrading guide.

      Once you've completed the SDK installation, you can start learning about development on the Android framework by reading the Developer's Guide. The SDK package -also includes a wide variety of very helpful code samples.

      +also includes a wide variety of code samples specific to each Android +platform. You can find the samples at this location:

      + +

      <sdk>/platforms/android-<version>/samples/

      Please note that you are currently viewing a local, offline version of the Android developer documentation. The offline documentation offers the same diff --git a/docs/html/publish/index.jd b/docs/html/publish/index.jd deleted file mode 100644 index 63f2e68e5449281b538ac4038bff1623b4c62e68..0000000000000000000000000000000000000000 --- a/docs/html/publish/index.jd +++ /dev/null @@ -1,5 +0,0 @@ -publish=true -page.title=Publish Your Application -@jd:body - -FIXME diff --git a/docs/html/publish/publish_toc.cs b/docs/html/publish/publish_toc.cs deleted file mode 100644 index c6f5c6535b6fcd22c0329b12de2b41b7c0eb1994..0000000000000000000000000000000000000000 --- a/docs/html/publish/publish_toc.cs +++ /dev/null @@ -1 +0,0 @@ -

      FIXME diff --git a/docs/html/reference/reference_toc.cs b/docs/html/reference/reference_toc.cs deleted file mode 100644 index 60e9d5f60e6fe0ae33115c56ad5f424523879724..0000000000000000000000000000000000000000 --- a/docs/html/reference/reference_toc.cs +++ /dev/null @@ -1 +0,0 @@ - FIXME diff --git a/docs/html/robots.txt b/docs/html/robots.txt index a8729444413854ba0c0bb026f6911d477eaf02c6..085b79dc1b68ff7cef912bff1b07f714d5c0a7ca 100644 --- a/docs/html/robots.txt +++ b/docs/html/robots.txt @@ -3,4 +3,5 @@ Allow: / Disallow: /gae_shell/ Disallow: /assets/ Disallow: /images/ +Disallow: /sdk/preview/ Sitemap: http://developer.android.com/sitemap.txt diff --git a/docs/html/samples/index.jd b/docs/html/samples/index.jd index c5c0b7132eb9bcd9f8427cba8489c97c5b52a94a..06afd07f8ded724734f39b48029ae10dec3f9b66 100644 --- a/docs/html/samples/index.jd +++ b/docs/html/samples/index.jd @@ -18,6 +18,5 @@ page.onlyfortemplate=codesite

      To run these samples, you should import them into -Eclipse or use -activitycreator.py, as described in the Installing the SDK.

      +Eclipse or build them with Ant, as described in +Developing in Other IDEs.

      diff --git a/docs/html/sdk/1.0_r1/index.jd b/docs/html/sdk/1.0_r1/index.jd index b6e0e9f20992dea4bffb364c1cdf080d7dd9c466..6ef860f539513b8f837805a602c823cd8fcee17e 100644 --- a/docs/html/sdk/1.0_r1/index.jd +++ b/docs/html/sdk/1.0_r1/index.jd @@ -20,6 +20,9 @@ sdk.linux_checksum=2660b4029039b7d714e59827e9a9a11d @jd:body +

      For more information on this SDK release, read the +Release Notes.

      +

      Included in this SDK

      Development tools

      diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.0_r1/requirements.jd new file mode 100644 index 0000000000000000000000000000000000000000..af0667548dccbf826c52e74fbcc276e6622d990a --- /dev/null +++ b/docs/html/sdk/1.0_r1/requirements.jd @@ -0,0 +1,45 @@ +page.title=System Requirements +sdk.version=1.0_r1 + + +@jd:body + +

      The sections below describe the system and software requirements for +developing Android applications using the Android SDK tools included in Android 1.0 SDK, Release 1.

      + +

      System and Software Requirements

      +

      The following systems and development environments are supported by this SDK.

      + +

      Supported Operating Systems:

      +
        +
      • Windows XP or Vista
      • +
      • Mac OS X 10.4.8 or later (x86 only)
      • +
      • Linux (tested on Linux Ubuntu Dapper Drake)
      • +
      + +

      Supported Development Environments:

      +
        +
      • Eclipse IDE + +
      • +
      • Other development environments or IDEs +
          +
        • JDK 5 or JDK 6 (JRE alone is not sufficient)
        • +
        • Apache Ant 1.6.5 or later for Linux and Mac, 1.7 or later for Windows
        • +
        • Not compatible with Gnu Compiler for Java (gcj)
        • +
        +
      • +
      + +

      Note: If JDK is already installed on your development computer, please take a moment to make sure that it meets the version requirements listed above. In +particular, note that some Linux distributions may include JDK 1.4 or Gnu Compiler for Java, both of which are not supported for Android development.

      \ No newline at end of file diff --git a/docs/html/sdk/1.0_r2/index.jd b/docs/html/sdk/1.0_r2/index.jd index 2446c0913ac51e4d0eb44fe769900929ad4385dc..a1989ba93939ebbfa9ca64f8a1e607074bc7c7ef 100644 --- a/docs/html/sdk/1.0_r2/index.jd +++ b/docs/html/sdk/1.0_r2/index.jd @@ -20,6 +20,9 @@ sdk.linux_checksum=a1f3b6d854596f850f5008856d0f380e @jd:body +

      For more information on this SDK release, read the +Release Notes.

      +

      Included in this SDK

      Development tools

      diff --git a/docs/html/sdk/1.1_r1/index.jd b/docs/html/sdk/1.1_r1/index.jd index c4a9bf0e7f6367ae6d1d4231b452be58e2e0d7b3..f6582162fb919ef94f8a2019197e409684e94c68 100644 --- a/docs/html/sdk/1.1_r1/index.jd +++ b/docs/html/sdk/1.1_r1/index.jd @@ -1,5 +1,6 @@ page.title=Android 1.1 SDK, Release 1 +sdk.not_latest_version=true sdk.version=1.1_r1 sdk.date=February 2009 @@ -18,6 +19,9 @@ sdk.linux_checksum=ebcb16b0cd4aef198b4dd9a1418efbf1 @jd:body +

      For more information on this SDK release, read the +Release Notes.

      +

      SDK Contents

      Development tools

      diff --git a/docs/html/sdk/1.1_r1/installing.jd b/docs/html/sdk/1.1_r1/installing.jd index d5a7106483636287a1735cb04ba0ed01eea45d87..2da24799f95b8eff28e94d8d5e3fff58bb7b9915 100644 --- a/docs/html/sdk/1.1_r1/installing.jd +++ b/docs/html/sdk/1.1_r1/installing.jd @@ -242,7 +242,7 @@ href="{@docRoot}reference/index.html">Reference tab

      Explore the SDK

      • Get an overview of the development +href="{@docRoot}guide/developing/tools/index.html">development tools that are available to you
      • Read the overviews of how to develop in Eclipse/ADT or diff --git a/docs/html/sdk/1.5_r1/index.jd b/docs/html/sdk/1.5_r1/index.jd index 412887a95257ddc07d3f9be3796933744fc0ea5a..438ee4bb80ce195d85b20255066366a52e387354 100644 --- a/docs/html/sdk/1.5_r1/index.jd +++ b/docs/html/sdk/1.5_r1/index.jd @@ -2,51 +2,74 @@ sdk.version=1.5 sdk.rel.id=1 sdk.date=April 2009 -sdk.win_download= -sdk.win_bytes= -sdk.win_checksum= +sdk.win_download=android-sdk-windows-1.5_r1.zip +sdk.win_bytes=176263368 +sdk.win_checksum=42be980eb2d3efaced01ea6c32c0045f -sdk.mac_download= -sdk.mac_bytes= -sdk.mac_checksum= +sdk.mac_download=android-sdk-mac_x86-1.5_r1.zip +sdk.mac_bytes=167848675 +sdk.mac_checksum=5b2a8d9f096032db4a75bfa0d689a51b -sdk.linux_download= -sdk.linux_bytes= -sdk.linux_checksum= +sdk.linux_download=android-sdk-linux_x86-1.5_r1.zip +sdk.linux_bytes=162938845 +sdk.linux_checksum=2addfd315da0ad8b5bde6b09d5ff3b06 -page.title=Download Android SDK +page.title=Android 1.5 SDK, Release 1 @jd:body +

        For more information on this SDK release, read the +Release Notes.

        +

        SDK Contents

        Development tools

        -

        The SDK includes a variety of tools for developing and debugging application code and designing an application UI. You can read about the tools in the +

        The SDK includes a full set of tools for developing and debugging application code and designing an application UI. You can read about the tools in the Dev Guide and access them in the <sdk>/tools/ directory. -

        The tools package included in this SDK includes many updates from that provided in the previous SDK and requires you to migrate your applications to the new development environment. For details, see the Upgrading the SDK document.

        +

        The tools package in this SDK includes updates from those provided in the previous SDK. The tools also require a different project structure. To use the new tools, you need to migrate your applications to the new development environment. For more information about how to migrate, see Upgrading the SDK. + +

        For more information about the new tools features, see the SDK Release Notes. -

        System Images

        +

        Android Platforms

        -

        The Android system images listed below are included in this SDK. For more information about a system image — features, applications included, localizations, API changes, and so on — see its Version Notes.

        +

        This SDK includes multiple Android platform versions that you use to develop applications. For each version, both a fully compliant Android library and system image are provided. The table below lists the platform versions included in this SDK. For more information about a platform version — features, applications included, localizations, API changes, and so on — see its Version Notes.

        - + - + - + + + +
        System ImageAPI LevelNotesDescriptionPlatformAPI LevelNotesDescription
        Android 1.5 3 Version NotesIncludes a set of standard development applications. Includes a standard Android 1.5 library and system image with a set of development applications. Does not include any external libraries (such as the Maps external library).
        Android 1.1 2 Version NotesIncludes a set of standard development applications. Includes a compliant Android 1.1 library and system image with a set of development applications. Also includes the Maps external library (due to legacy build system issues).
        + +

        SDK Add-Ons

        +

        An SDK add-on provides a development environment for an Android external library or a customized (but fully compliant) Android system image. This SDK includes the SDK add-on listed below. The Android system API Level required by the add-on is noted.

        + + + + + + + + + +
        Add-OnAPI LevelNotesDescription
        Google APIs3 Includes the com.google.android.maps external library, a compliant +system image, a {@link android.location.Geocoder Geocoder} +backend service implementation, documentation, and sample code.
        @@ -55,7 +78,6 @@ page.title=Download Android SDK

        You can look at a variety of tutorials and samples in the Dev Guide and access the sample code itself in the <sdk>/platforms/android-1.5/samples/ directory of the SDK package. Note the new location — the SDK now includes multiple platform versions that you can develop against and each has its own sample code directory.

        - diff --git a/docs/html/sdk/1.5_r1/installing.jd b/docs/html/sdk/1.5_r1/installing.jd index a1f7cffb0576e0c4d512be6ee04a9d9cc5ff4901..ac6af616d9e805c1a4d28bda0488f04719e254c9 100644 --- a/docs/html/sdk/1.5_r1/installing.jd +++ b/docs/html/sdk/1.5_r1/installing.jd @@ -5,6 +5,328 @@ sdk.date=April 2009 page.title=Installing the Android SDK @jd:body -

        See the Download page for more information.

        + +

        This page describes how to install the Android SDK and set up your +development environment. If you haven't downloaded the SDK, you can +do so from the +Download page. Once you've downloaded +the SDK, return here.

        + +

        If you encounter any problems during installation, see the +Installation Notes at the bottom of +this page.

        + +

        Upgrading?

        +

        If you have already developed applications using an earlier version +of the SDK, please read +Upgrading the +SDK, instead. +

        + + +

        Preparing for Installation

        + +

        Before you begin, take a moment to confirm that your development machine meets the +System Requirements. +

        + +

        If you will be developing on Eclipse with the Android Development +Tools (ADT) Plugin — the recommended path if you are new to +Android — make sure that you have a suitable version of Eclipse +installed on your computer (3.3 or newer). If you need to install Eclipse, you can +download it from this location:

        + +

        http://www.eclipse.org/downloads/

        + +

        A Java or RCP version of Eclipse is recommended.

        + +

        Installing the SDK

        + +

        After downloading the SDK, unpack the .zip archive to a suitable location on your machine. +By default, the SDK files are unpacked into a directory named +android_sdk_<platform>_<release>. +The directory contains a local copy of the documentation (accessible by opening +documentation.html in your browser) and the subdirectories +tools/, add-ons/, platforms/, and others. Inside +each subdirectory of platforms/ you'll find samples/, which includes +code samples that are specific to each version of the platform.

        + +

        Make a note of the name and location of the unpacked SDK directory on your system — you +will need to refer to the SDK directory later, when setting up the Android plugin or when +using the SDK tools.

        + +

        Optionally, you may want to add the location of the SDK's primary tools directory +to your system PATH. The primary tools/ directory is located at the root of the +SDK folder. Adding tools to your path lets you run Android Debug Bridge (adb) and +the other command line tools without +needing to supply the full path to the tools directory.

        +
          +
        • On Linux, edit your ~/.bash_profile or ~/.bashrc file. Look + for a line that sets the PATH environment variable and add the + full path to the tools/ directory to it. If you don't + see a line setting the path, you can add one:
        • + +
            export PATH=${PATH}:<your_sdk_dir>/tools
          + +
        • On a Mac, look in your home directory for .bash_profile and + proceed as for Linux. You can create the .bash_profile if + you haven't already set one up on your machine.
        • + +
        • On Windows, right-click on My Computer, and select Properties. + Under the Advanced tab, hit the Environment Variables button, and in the + dialog that comes up, double-click on Path (under System Variables). Add the full path to the + tools/ directory to the path.
        • +
        + +

        Note that, if you update your SDK in the future, you +should remember to update your PATH settings to point to the new location, if different.

        + +

        If you will be using the Eclipse IDE as your development environment, +the next section describes how to install the Android Development Tools plugin and set up Eclipse. +If you choose not to use Eclipse, you can +develop Android applications in an IDE of your choice and then compile, debug and deploy using +the tools included in the SDK (skip to Next Steps).

        + + +

        Installing the ADT Plugin for Eclipse

        + +

        Android offers a custom plugin for the Eclipse IDE, called Android +Development Tools (ADT), that is designed to give you a powerful, +integrated environment in which to build Android applications. It +extends the capabilites of Eclipse to let you quickly set up new Android +projects, create an application UI, add components based on the Android +Framework API, debug your applications using the Android SDK tools, and even export +signed (or unsigned) APKs in order to distribute your application.

        + +

        In general, using Eclipse with ADT is a highly recommended +approach to Android development and is the fastest way to get started. +(If you prefer to work in an IDE other than Eclipse, +you do not need to install Eclipse or ADT, instead, you can directly +use the SDK tools to build and debug your application.)

        + +

        Once you have Eclipse installed, as described in Preparing for +Installation, follow the steps below to +download the ADT plugin and install it in your respective Eclipse +environment.

        + + + + + + + +
        Eclipse 3.3 (Europa)Eclipse 3.4 (Ganymede)
        + +
          +
        1. Start Eclipse, then select Help > Software Updates +> Find and Install....
        2. +
        3. In the dialog that appears, select Search for new features to install +and click Next.
        4. +
        5. Click New Remote Site.
        6. +
        7. In the resulting dialog box, enter a name for the remote site (e.g. "Android Plugin") and + enter the URL: +
          https://dl-ssl.google.com/android/eclipse/
          +

          If you have trouble aqcuiring the plugin, try using "http" in the URL, + instead of "https" (https is preferred for security reasons).

          +

          Click OK.

        8. +
        9. You should now see the new site added to the search list (and checked). + Click Finish.
        10. +
        11. In the subsequent Search Results dialog box, select the checkbox for the + "Android Plugin". + This will select the nested tools: "Android DDMS" and "Android Development Tools". + Click Next.
        12. +
        13. Read and accept the license agreement, then click Next.
        14. +
        15. On the following Installation window, click Finish.
        16. +
        17. The ADT plugin is not digitally signed. Accept the installation anyway + by clicking Install All.
        18. +
        19. Restart Eclipse.
        20. +
        + +
        + + +
          +
        1. Start Eclipse, then select Help > Software Updates....
        2. +
        3. In the dialog that appears, click the Available Software tab.
        4. +
        5. Click Add Site...
        6. +
        7. Enter the Location: +
          https://dl-ssl.google.com/android/eclipse/
          +

          If you have trouble aqcuiring the plugin, try using "http" in the Location URL, + instead of "https" (https is preferred for security reasons).

          +

          Click OK.

        8. +
        9. Back in the Available Software view, you should see the plugin listed by the URL, + with "Developer Tools" nested within it. Select the checkbox next to + Developer Tools and click Install...
        10. +
        11. On the subsequent Install window, "Android DDMS" and "Android Development Tools" + should both be checked. Click Next.
        12. +
        13. Read and accept the license agreement, then click Finish.
        14. +
        15. Restart Eclipse.
        16. +
        + +
        + +

        Now modify your Eclipse preferences to point to the Android SDK directory:

        +
          +
        1. Select Window > Preferences... to open the Preferences + panel (Mac: Eclipse > Preferences).
        2. +
        3. Select Android from the left panel.
        4. +
        5. For the SDK Location in the main panel, click Browse... and +locate your downloaded SDK directory.
        6. +
        7. Click Apply, then OK.
        8. +
        + +

        Done! If you haven't encountered any problems, then you're ready to +begin developing Android applications. See the +Next Steps section for suggestions on how to start.

        + + +

        Troubleshooting ADT Installation

        +

        +If you are having trouble downloading the ADT plugin after following the steps above, here are +some suggestions:

        + +
          +
        • If Eclipse can not find the remote update site containing the ADT plugin, try changing + the remote site URL to use http, rather than https. That is, set the Location for the remote site to: +
          http://dl-ssl.google.com/android/eclipse/
        • +
        • If you are behind a firewall (such as a corporate firewall), make + sure that you have properly configured your proxy settings in Eclipse. + In Eclipse 3.3/3.4, you can configure proxy information from the main + Eclipse menu in Window (on Mac, Eclipse) > + Preferences > General > + Network Connections.
        • +
        +

        +If you are still unable to use Eclipse to download the ADT plugin as a remote update site, you +can download the ADT zip file to your local machine and manually install the it: +

        +
          +
        1. Download the ADT zip file (do not unpack it).
        2. +
        3. Follow steps 1 and 2 in the default install instructions (above).
        4. +
        5. In Eclipse 3.3, click New Archive Site....
          + In Eclipse 3.4, click Add Site..., then Archive...
        6. +
        7. Browse and select the downloaded zip file.
        8. +
        9. Follow the remaining procedures, above, starting from steps 5.
        10. +
        +

        To update your plugin once you've installed using the zip file, you will have to +follow these steps again instead of the default update instructions.

        + +

        Other install errors

        + +

        Note that there are features of ADT that require some optional +Eclipse components (for example, WST). If you encounter an error when +installing ADT, your Eclipse installion might not include these components. +For information about how to quickly add the necessary components to your +Eclipse installation, see the troubleshooting topic +ADT +Installation Error: "requires plug-in org.eclipse.wst.sse.ui".

        + +

        For Linux users

        +

        If you encounter this error when installing the ADT Plugin for Eclipse: +

        +An error occurred during provisioning.
        +Cannot connect to keystore.
        +JKS
        +

        +...then your development machine lacks a suitable Java VM. Installing Sun +Java 6 will resolve this issue and you can then reinstall the ADT +Plugin.

        + + +

        Next Steps

        +

        Once you have completed installation, you are ready to +begin developing applications. Here are a few ways you can get started:

        + +

        Learn about Android

        +
          +
        • Take a look at the Dev + Guide and the types of information it provides
        • +
        • Read an introduction to Android as a platform in What is + Android?
        • +
        • Learn about the Android framework and how applications run on it in + Application + Fundamentals
        • +
        • Take a look at the Android framework API specification in the Reference tab
        • +
        + +

        Explore the SDK

        + + +

        Explore some code

        +
          +
        • Set up a Hello + World application (highly recommended, especially for Eclipse users)
        • +
        • Follow the + Notepad Tutorial to build a full Android application
        • +
        • Create a new project for one of the other sample applications + included in <sdk>/platforms/<platfrom>/samples, + then compile and run it in your development environment
        • +
        + +

        Visit the Android developer groups

        +
          +
        • Take a look at the Community tab to see a list of + Android developers groups. In particular, you might want to look at the + Android + Developers group to get a sense for what the Android developer + community is like.
        • +
        + + +

        Installation Notes

        + +

        Ubuntu Linux Notes

        + +
          +
        • If you need help installing and configuring Java on your + development machine, you might find these resources helpful: + +
        • +
        • Here are the steps to install Java and Eclipse, prior to installing + the Android SDK and ADT Plugin. +
            +
          1. If you are running a 64-bit distribution on your development + machine, you need to install the ia32-libs package using + apt-get:: +
            apt-get install ia32-libs
            +
          2. +
          3. Next, install Java:
            apt-get install sun-java6-bin
          4. +
          5. The Ubuntu package manager does not currently offer an Eclipse 3.3 + version for download, so we recommend that you download Eclipse from + eclipse.org (http://www.eclipse.org/ + downloads/). A Java or RCP version of Eclipse is recommended.
          6. +
          7. Follow the steps given in previous sections to install the SDK + and the ADT plugin.
          8. +
          +
        • +
        + +

        Other Linux Notes

        + +
          +
        • If JDK is already installed on your development computer, please + take a moment to make sure that it meets the version requirements listed + in the System Requirements. + In particular, note that some Linux distributions may include JDK 1.4 or Gnu + Compiler for Java, both of which are not supported for Android development.
        • +
        + diff --git a/docs/html/sdk/1.5_r1/requirements.jd b/docs/html/sdk/1.5_r1/requirements.jd index c3ee8f7eac44f52c8d667e7880b0c9b409d2c13e..4ed38a741261c58ca680afbd35b0399ecfee3719 100644 --- a/docs/html/sdk/1.5_r1/requirements.jd +++ b/docs/html/sdk/1.5_r1/requirements.jd @@ -16,8 +16,9 @@ page.title=System Requirements
        • Eclipse 3.3 (Europa), 3.4 (Ganymede)
            +
          • Recommended Eclipse IDE packages: Eclipse IDE for Java EE Developers, Eclipse IDE for Java Developers, Eclipse for RCP/Plug-in Developers
          • Eclipse JDT plugin (included in most Eclipse IDE packages)
          • -
          • WST (optional, but needed for the Android Editors feature; included in most Eclipse IDE packages)
          • +
          • Eclipse Classic IDE package is not supported.
        • JDK 5 or JDK 6 (JRE alone is not sufficient)
        • diff --git a/docs/html/sdk/1.5_r1/upgrading.jd b/docs/html/sdk/1.5_r1/upgrading.jd index 532313110cb3e4c8cc8fbc653a89a627fb6b03a1..0a12d6223415421883b1890fbd06ca1bc72fc6af 100644 --- a/docs/html/sdk/1.5_r1/upgrading.jd +++ b/docs/html/sdk/1.5_r1/upgrading.jd @@ -2,175 +2,394 @@ page.title=Upgrading the SDK sdk.version=1.5_r1 @jd:body - +
      +

      This document describes how to move your development environment and existing +Android applications from an Android 1.0 or 1.1 SDK to the Android 1.5 SDK. +If you are migrating applications from an SDK older than 1.0, please also read the upgrading +document available in the Android 1.0 SDK package.

      -
      -
      +

      There are several compelling reasons to upgrade, such as new SDK tools +that make developing more efficient and new APIs that allow you to expand the feature-set +of your applications. However, even if you or your applications don't require these enhancements, +it's important that you upgrade to ensure that your applications run properly on the +Android 1.5 platform.

      -

      Upgrading quickview

      -
        -
      • The Android 1.5 SDK uses a new project structure and a new ADT plugin (ADT 0.9).
      • -
      • To move existing projects into the SDK, you must make some minor changes in your development environment.
      • -
      • The new ADT plugin (ADT 0.9) is not compatible with projects created in previous SDKs.
      • -
      • You need to uninstall your existing ADT plugin, before installing ADT 0.9.
      • +

        The Android 1.5 platform will soon be deployable to devices around the world. +If you have already released Android applications to the public, you should +test the forward-compatibility of your applications on the latest version of the platform +as soon as possible. It's unlikely that you'll encounter breakage in your applications, but +in the interest of maintaining the best user experience, you should take no risks. +So, please install the new Android SDK and test your applications on Android 1.5.

        -
      +

      For more information on new SDK features and system changes, +see the Android 1.5 Version Notes.

      - -
      -
      -

      See the Download page for more information.

      +

      Install the SDK

      -
        -
      1. Select Help > Software Updates > Find and Install....
      2. -
      3. Select Search for updates of the currently installed features and click Finish.
      4. -
      5. If any update for ADT is available, select and install.
      6. -
      7. Restart Eclipse.
      8. +
      9. Select Help > Software Updates > + Manage Configuration.
      10. +
      11. Expand the list in the left panel to reveal the installed tools.
      12. +
      13. Right-click "Android Editors" and click Uninstall. Click OK + to confirm.
      14. +
      15. Restart Eclipse. +

        (Do not uninstall "Android Development Tools".)

      -

      Alternatively,

      + + +
        -
      1. Select Help > Software Updates > Manage Configuration.
      2. +
      3. Select Help > Software Updates.
      4. +
      5. Select the Installed Software tab.
      6. +
      7. Select "Android Editors". Click Uninstall.
      8. +
      9. In the next window, be sure "Android Editors" is checked, then click Finish + to uninstall.
      10. +
      11. Restart Eclipse. +

        (Do not uninstall "Android Development Tools".)

      12. +
      + + + + + +

      Install the 0.9 ADT plugin

      -
    12. Navigate down the tree and select Android Development Tools <version>
    13. -
    14. Select Scan for Updates under Available Tasks.
    15. +

      Only install the new plugin once you've completed the procedure to +Uninstall your previous ADT plugin.

      + + + + +
      Eclipse 3.3 (Europa)Eclipse 3.4 (Ganymede)
      + +
        +
      1. Select Help > Software Updates > + Find and Install.
      2. +
      3. Select Search for new features to install.
      4. +
      5. Select the Android plugin entry by checking the box next to it, + then click Finish. +

        (Your original entry for the plugin should still be here. If not, see the guide + to Installing the ADT Plugin.) +

      6. +
      7. In the results, expand the entry for the Android plugin and + be sure that "Developer Tools" is checked, then click Next. + (This will install "Android DDMS" and "Android Development Tools".)
      8. +
      9. Read and accept the license agreement, then click Next. +
      10. In the next window, click Finish to start installation.
      11. +
      12. The ADT plugin is not digitally signed. Accept the installation anyway by clicking + Install All.
      13. +
      14. Restart Eclipse.
      +
        -
      1. Select Help > Software Updates...
      2. -
      3. Select the Installed Software tab.
      4. -
      5. Click Update...
      6. -
      7. If an update for ADT is available, select it and click Finish.
      8. +
      9. Select Help > Software Updates.
      10. +
      11. Select the Available Software tab.
      12. +
      13. Expand the entry for the Andriod plugin (may be listed as the location URL) + and select "Developer Tools" by checking the box next to it, then click + Install.
      14. +
      15. On the next window, "Android DDMS" and "Android Development Tools" + should both be checked. Click Finish.
      16. Restart Eclipse.
      -

      Update your Eclipse SDK Preferences

      +

      If you encounter problems, ensure your ADT is fully uninstalled and then +follow the guide to +Installing the ADT Plugin +for Eclipse.

      + +

      Update your Eclipse SDK Preferences

      The last step is to update your Eclipse preferences to point to the new SDK directory:

        -
      1. Select Window > Preferences... to open the Preferences panel. (Mac OSX: Eclipse > Preferences)
      2. +
      3. Select Window > Preferences to open the Preferences + panel (Mac: Eclipse > Preferences).
      4. Select Android from the left panel.
      5. -
      6. For the SDK Location in the main panel, click Browse... and locate the SDK directory.
      7. +
      8. For the SDK Location in the main panel, click Browse + and locate your SDK directory.
      9. Click Apply, then OK.
      -

      Migrate Your Applications, if Necessary

      -

      If (and only if) you have written apps in an SDK released previous to -the Android 1.0 SDK, you will need to migrate your applications. After -installing the new SDK and updating the ADT Plugin (if applicable), you -may encounter breakages in your application code, due to -framework and API changes. You'll need to update your code to match the -latest APIs.

      +

      Update Your Projects

      + +

      You will now need to update any and all Android projects that you have +developed using a previous version of the Android SDK.

      + + +

      Eclipse users

      + +

      If you use Eclipse to develop applications, use the following procedure to +update each project:

      + +
        +
      1. Right-click on the individual project (in the Package Explorer) + and select Properties.
      2. +
      3. In the properties, open the Android panel and select a "build target" to compile + against. This SDK offers the Android 1.1 and Android 1.5 platforms to choose from. When + you are initially updating your projects to the new SDK, we recommend that you select a build + target with the Android 1.1 platform. Click Apply, then + OK.
      4. +
      + +

      The new plugin creates a gen/ folder in your project, in which it puts the +R.java file +and all automatically generated AIDL java files. If you get an error such as +The type R is already defined, +then you probably need to delete your old R.java or your old auto-generated +AIDL Java files in the src/ folder. +(This does not apply to your own hand-crafted parcelable AIDL java files.)

      + +

      Note that, with the Android 1.5 SDK, there is a new process for running +applications in the Android Emulator. +Specifically, you must create an Android Virtual Device (AVD) before you can launch an instance +of the Emulator. Before attempting to run your applications with the new SDK, +please continue with the section below to +Migrate Your Applications.

      + + +

      Ant users

      + +

      If you build your projects using the Ant tool (rather than with Eclipse), note the +following changes with the new SDK tools.

      + +

      build.xml has changed

      + +

      You must re-create your build.xml file.

      + +

      If you had customized your build.xml, first make a copy of it:

      + +
      +$ cd my-project
      +$ cp build.xml build.xml.old
      +
      + +

      Now use the new android tool (located in your_sdk/tools/) +to create a new build.xml that references +a specific platform target:

      + +
      $ android update project --path /path/to/my-project --target 1
      + +

      The "target" corresponds to an Android platform library (including any add-ons, such as +Google APIs) that you would like to build your project against. You can view a list of available +targets (and their corresponding integer ID) with the command, android list targets. +When you are initially updating your projects to the new SDK, we recommend that you select the +first target ("1"), which uses the Android 1.1 platform library.

      + +

      A gen/ folder will be created the first time you build and your R.java and +your AIDL Java files will be generated in here. You must remove +the old R.java and old auto-generated AIDL java files from the +src/ folder. (This +does not apply to your own hand-crafted parcelabe AIDL java files.)

      + +

      Note: The "activitycreator" tool has been replaced +by the new "android" tool. For information on creating new projects with the android tool, +see the documentation about Developing +In Other IDEs.

      + +

      Note that, with the Android 1.5 SDK, there is a new process for running +applications in the Android Emulator. +Specifically, you must create an Android Virtual Device (AVD) before you can launch an instance +of the Emulator. Before attempting to run your applications with the new SDK, +please continue with the section below to +Migrate Your Applications.

      + + +

      Migrate Your Applications

      + +

      After you have completed the process above to Update Your +Projects, you are strongly encouraged to run each of your applications in an instance +of the emulator running the Android 1.5 system image. It's possible (however, unlikely) +that you'll encounter some breakage in your application when you run your applications on +the Android 1.5 system image. Whether you believe your application will be affected by +platform changes or not, it's very important that you test the application's +forward-compatibility on Android 1.5.

      + +

      To test forward-compatibility, simply run your existing application (as-is) on an Android +Emulator that's running the Android 1.5 system image. The following procedure will guide +you through the process to running your existing applications on an emulator. Please read +the following guide completely before you begin.

      -

      One way to start is to open your project in Eclipse and see where the ADT -identifies errors in your application. You can also look up -specific changes in the Android APIs in the -android-1.5.html#api-changes -Android 1.5 Version Notes +

      To test your application on an emulator running Android 1.5:

      +
        +
      1. Update Your Project (you should have done this + already, in the section above).
      2. +
      3. Run your existing project, as-is, on an emulator running the Android 1.5 system image. +

        As mentioned in the guide to Update Your Projects, + you should have selected a "build + target" of "1", which compiles your application against the Android 1.1 system image, so there + should be no new errors in your code.

        +

        Eclipse users: follow the + Eclipse guide to + Running Your Application.

        +

        Ant users: follow the + Ant guide to + Running Your Application +

        During the procedure to Running Your Application, select a "deployment target" + for the AVD that includes the Android 1.5 platform. + If your application utilizes the Google Maps APIs (i.e., + MapView), be certain to select a target that includes the Google APIs.

        +

        Once you complete the procedures to run your application in your respective environment, + linked above, return here.

        +
      4. +
      5. With your application running in the emulator, perform all regular testing on the application + to ensure that it functions normally (in both landscape and portrait orientations).
      6. +
      + +

      Chances are, your application runs just fine on the Android 1.5 platform — +new devices will be able to safely install and run your application and +current users who update their devices will be able to continue using your application as usual. +However, if something doesn't work the way you expect, then you might need to revisit +your project and make any necessary changes to your code.

      + +

      You can check for code breakages caused by API changes by opening your project +in Eclipse, changing the "build target" to one using the Android 1.5 platform, +and see where the ADT identifies errors in your code.

      + + +

      Future-proof your apps

      + +

      There have been several API additions made for this release, but there have been +very few actual API changes. Only a couple (relatively unused) elements +have been removed and a few have been deprecated, so your applications written with the +Android 1.1 system library should work just fine. However, +your application is more likely to encounter problems on Android 1.5 +if it performs any of the following:

      + +
        +
      • Uses internal APIs. That is, APIs that are not officially supported + and not available in the reference documentation. Any un-official APIs are always subject + to change (which is why they're un-official) and some have indeed changed. +
      • +
      • Directly manipulates system settings. There are some settings (such as + GPS, data roaming, bluetooth and others) that used to be writable by + applications but have been changed so that they can only be explicitly modified by the user + through the system settings. Refer to {@link android.provider.Settings.Secure} + to see which settings are now secured and cannot be directly changed by your application. +
      • +
      • Uses View hierarchies that are unreasonably deep (more than 10 or so levels) or + broad (more than 30 total). View hierarchies this big have always been troublesome, but + Android 1.5 is much more efficient at exposing this and your application may crash. +
      • +
      • Makes assumptions about the available hardware. With new support for soft keyboards, + not all devices will have full QWERTY keyboards on the hardware. So if your application + listens for special keypress events that only occur on a keypad, then your application + should degrade gracefully when there is no keyboard available. +
      • +
      • Performs its own layout orientation changes based on the acceletometer (or via other + sensors). Some devices running Android 1.5 will automatically rotate the orientation + (and all devices have the option to turn on auto-rotation), so if your application also + attempts to rotate the orientation, it can result in strange behavior. In addition, if your + application uses the accelerometer to detect shaking and you do not want to rotate the + orientation, then you should lock the current orientation with + android:screenOrientation. +
      • +
      -document.

      +

      Please read our blog post on Future-Proofing +Your Apps for more information on the issues mentioned above.

      + +

      For information +about other changes made to Android 1.5, refer to the following documents:

      +

      If you have additional trouble updating your code, visit the Android Developers Group to seek help from other Android developers.

      - -

      If you have modified one of the ApiDemos applications and would like to migrate it -to the new SDK, note that you will need to uninstall the version of ApiDemos that comes -preinstalled in the emulator. For more information, or if you encounter an "reinstallation" -error when running or installing ApiDemos, see the troubleshooting topic -I can't install ApiDemos -apps in my IDE because of a signing error for information about how to solve the problem.

      ---> \ No newline at end of file diff --git a/docs/html/sdk/RELEASENOTES.jd b/docs/html/sdk/RELEASENOTES.jd index bad71a2a59da3894cc7a5a9a3a02ad2f0538ffd7..c44cef3a55fba62b0aab489b48950721899ac342 100644 --- a/docs/html/sdk/RELEASENOTES.jd +++ b/docs/html/sdk/RELEASENOTES.jd @@ -1,36 +1,240 @@ page.title=SDK Release Notes @jd:body -

      This document provides version-specific information about Android SDK releases. For the latest known issues, please ensure that you're viewing this page at: http://developer.android.com/sdk/RELEASENOTES.html.

      +

      This document provides version-specific information about Android SDK +releases. For the latest known issues, please ensure that you're viewing this +page at: +http://developer.android.com/sdk/RELEASENOTES.html.

      + +

      Android 1.5 SDK, Release 1

      + +

      This SDK provides updates to the development tools and Android system that +you use to create applications for compliant Android-powered devices.

      + +

      Release Overview

      + +

      This SDK release includes many new features for developers. Highlights of the +changes include:

      + +
        +
      • Multiple versions of the Android platform are included (Android 1.1, +Android 1.5). The tools are updated to let you deploy your application +on any platform in the SDK, which helps you ensure forward-compitility and, +if applicable, backward-compatibility.
      • +
      • Introduces Android +Virtual Devices — (AVD) configurations of options that you +run in the emulator to better model actual devices. Each AVD gets its +own dedicated storage area, making it much easier to work with multiple emulators +that are running concurrently.
      • +
      • Support for SDK add-ons, which extend the +Android SDK to give you access to one or more external Android libraries and/or +a customized (but compliant) system image that can run in the emulator.
      • +
      • The new Eclipse ADT plugin (version 0.9.x) offers new Wizards to let you +create projects targetted for specific Android configurations, generate XML +resources (such as layouts, animations, and menus), generate alternate layouts, +and export and sign your application for publishing.
      • +
      • Improved JUnit support in ADT
      • +
      • Easier profiling of performance
      • +
      • Easier management of localized applications. You can now include or +exclude locale resources when building your APK from a single +Android project.
      • +
      • A new tool called "android" replaces the activitycreator script.
      • +
      + +

      For details about the Android platforms included in the SDK — including +bug fixes, features, and API changes — please read the Version Notes +documents available at left. For a list of Android platforms included in this +release, see the Download +page.

      + +

      Installation and Upgrade Notes

      + +

      If you've been developing an application using an Android 1.1 SDK, you need +to make a few changes to your development environment to migrate to the new SDK. +Tools and documentation are provided to assist you. No changes to the source +code of an existing application should be needed, provided that your application +is not using Android internal structures or APIs.

      + +

      To ensure that your existing application will work properly on a device +running the latest version of the Android platform, you are strongly encouraged +to migrate the application to the new SDK, compile it using the platform +matching the application's original API Level, and run it against the most +current platform.

      + +

      If you're installing the Android SDK for the first time, please see +the instructions in Installing the SDK. + +

      SDK Add-Ons

      + +

      This version of the SDK introduces support for SDK add-ons, which extend the +Android SDK to give you access to one or more external Android libraries and/or +a customized (but compliant) system image that can run in the emulator. The +purpose of an SDK add-on is to give you a way to develop applications for a +specific actual device (or family of devices) that extends the APIs available to +Android applications through external libraries or system customizations.

      + +

      From the perspective of your Android development environment, an SDK add-on +is similar to any of the Android platform targets included in the SDK — it +includes an external library, a system image, as well as custom emulator skins +and system properties. The add-on differs in that the Android platform it +provides may include customized UI, resources, or behaviors, a different set of +preinstalled applications, or other similar modifications. + +

      The SDK includes a single SDK add-on — the Google APIs add-on. The +Google APIs add-on gives your application access to the com.google.android.maps +external library that is included on many (if not most) Android-powered devices. +The Google APIs add-on also includes a {@link android.location.Geocoder Geocoder} +backend service implementation. For more information, see the "Maps External +Library" section below.

      + +

      Android Virtual Devices (AVDs)

      + +

      The SDK now gives you the capability to compile an application against any +one of several system targets, then run it in the emulator on top of any +compatible system image. There are two types of targets:

      +
        +
      • Targets that represent core Android platform versions.
      • +
      • Targets that are SDK add-ons, which typically provide application access to +one or more external libraries and/or a customized (but compliant) system image +that can run in the emulator. +
      + +

      A new tool called "android" lets you discover what targets and AVDs are +available to use.

      + +

      For more information about AVDs, see Android Virtual Devices + +

      Other Notes

      + +

      Maps External Library

      + +

      In previous versions of the SDK, the com.google.android.maps package was +included in the standard Android library and system image. In the Android 1.5 +SDK, that is not the case. The Android 1.5 library and system image do not +include the Maps external library (com.google.android.maps). However, the Maps +external library is available as part of the Google APIs add-on for the Android +SDK, downloadable from this location:

      + +

      http://code.google.com +/android/add-ons/google-apis

      + +

      For your convenience, the Google APIs add-on is included in the SDK.

      + +

      For information about how to register for a Maps API Key, see + +Obtaining a Maps API Key.

      + +

      USB Drivers for Windows

      + +

      If you are using Windows and want to develop or test your application on an +Android-powered device (such as the T-Mobile G1), you need an appropriate USB +driver. For your convenience, the Windows version of the Android SDK includes +these USB drivers that you can install, to let you develop on the device:

      + +
        +
      • USB driver for 32-bit XP and Vista
      • +
      • USB driver for 64-bit Vista only
      • +
      + +

      The USB driver files are located in the +<SDK>/usb_driver directory. For details and +installation instructions, see Setting Up a +Device for Development.

      +

      + +

      Resolved Issues, Changes

      + +

      Media

      +
        +
      • Updated documentation for {@link android.media.SoundPool +android.media.SoundPool}
      • +
      • {@link android.webkit.WebView} objects no longer automatically save +thumbnails. The {@link android.webkit.WebView#capturePicture() capturePicture()} +method will need to be called manually.
      • +
      + +

      Known Issues

      + +

      Sensor problems in Emulator

      + +
        +
      • If your application uses the Sensor API and you are running it in the +emulator on the Android 1.5 system image, you may experience problems. Your +application may generate ANR messages or crash when using the sensors. The +problem is being investigated.
      • +
      + +

      Other

      + +
        +
      • We regret to inform developers that Android 1.5 will not include support for +the Zilog Z80 processor architecture.
      • +
      +

      Android 1.1 SDK, Release 1

      -

      This SDK provides the development tools and Android system image you need to create applications for Android-powered devices. Applications developed on this SDK will be compatible with mobile devices running the Android 1.1 platform.

      +

      This SDK provides the development tools and Android system image you need to +create applications for Android-powered devices. Applications developed on this +SDK will be compatible with mobile devices running the Android 1.1 platform. +

      -

      This release provides an updated system image (Android 1.1), updated documentation, and the same set of development tools provided in the Android 1.0 r2 SDK. The updated system image includes bug fixes and some smaller features, as well as a few minor API changes from the 1.0 version.

      +

      This release provides an updated system image (Android 1.1), updated +documentation, and the same set of development tools provided in the Android 1.0 +r2 SDK. The updated system image includes bug fixes and some smaller features, +as well as a few minor API changes from the 1.0 version.

      -

      For details about the Android 1.1 system image included in the SDK — including bug fixes, features, and API changes — please read the Android 1.1 Version Notes.

      +

      For details about the Android 1.1 system image included in the SDK — +including bug fixes, features, and API changes — please read the Android 1.1 Version Notes.

      App Versioning for Android 1.1

      -

      If you are using this SDK to build an application that is compatible only with Android-powered devices running the Android 1.1 platform, please note that you must set the the android:minSdkVersion attribute in the application's manifest to the API Level of Android 1.1 — "2".

      +

      If you are using this SDK to build an application that is compatible +only with Android-powered devices running the Android 1.1 platform, +please note that you must set the the +android:minSdkVersion attribute in the application's manifest to +the API Level of Android 1.1 — "2".

      -

      Specifically, you specify the android:minSdkVersion attribute in a <uses-sdk> element as a child of <manifest> in the manifest file. When set, the attribute looks like this:

      +

      Specifically, you specify the android:minSdkVersion attribute in +a <uses-sdk> element as a child of +<manifest> in the manifest file. When set, the attribute +looks like this:

      <manifest>
         ...
      -  <uses-sdk minSdkVersion="2" />
      +  <uses-sdk android:minSdkVersion="2" />
         ...
       </manifest>
       
      -

      By setting android:minSdkVersion in this way, you ensure that users will only be able to install your application if their devices are running the Android 1.1 platform. In turn, this ensures that your application will function properly on their devices, especially if it uses APIs introduced in Android 1.1.

      +

      By setting android:minSdkVersion in this way, you ensure that +users will only be able to install your application if their devices are running +the Android 1.1 platform. In turn, this ensures that your application will +function properly on their devices, especially if it uses APIs introduced in +Android 1.1.

      -

      If your application uses APIs introduced in Android 1.1 but does not declare <uses-sdk minSdkVersion="2" />, then it will run properly on Android 1.1 devices but not on Android 1.0 devices.

      +

      If your application uses APIs introduced in Android 1.1 but does not declare +<uses-sdk android:minSdkVersion="2" />, then it will run properly on +Android 1.1 devices but not on Android 1.0 devices.

      -

      If your application does not use any new APIs introduced in Android 1.1, you can indicate Android 1.0 compatibility by removing minSdkVersion or setting the attribute to "1". However, before publishing your application, you must make sure to compile your application against the Android 1.0 system image (available in the Android 1.0 SDK), to ensure that it builds and functions properly for Android 1.0 devices. You should test the application against system images corresponding to the API Levels that the application is designed to be compatible with.

      +

      If your application does not use any new APIs introduced in Android 1.1, you +can indicate Android 1.0 compatibility by removing android:minSdkVersion or +setting the attribute to "1". However, before publishing your application, you +must make sure to compile your application against the Android 1.0 system image +(available in the Android 1.0 SDK), to ensure that it builds and functions +properly for Android 1.0 devices. You should test the application against system +images corresponding to the API Levels that the application is designed to be +compatible with.

      -

      If you are sure your application is not using Android 1.1 APIs and has no need to use them, you might find it easier to keep working in the Android 1.0 SDK, rather than migrating to the Android 1.1 SDK and having to do additional testing.

      +

      If you are sure your application is not using Android 1.1 APIs and has no +need to use them, you might find it easier to keep working in the Android 1.0 +SDK, rather than migrating to the Android 1.1 SDK and having to do additional +testing.

      ADT Plugin Compatibility

      @@ -52,7 +256,7 @@ application on the Android 1.1 emulator for the first time.

      If you're installing the Android SDK for the first time, please see the instructions in Installing the SDK. +href="{@docRoot}sdk/1.5_r1/installing.html">Installing the SDK.

      Other Notes

      @@ -67,7 +271,7 @@ for authentication to the server.

      Developers should note that the registration service for MapView is now active and Google Maps is actively enforcing the Maps API Key requirement. For information about how to register for a Maps API Key, see - + Obtaining a Maps API Key.

      USB Drivers for Windows

      @@ -136,9 +340,6 @@ are not working in this release. - - -

      Android 1.0 SDK, Release 2

      This SDK release includes the Android 1.0 platform and application API. @@ -154,12 +355,12 @@ added.

      Development Tools (ADT) Plugin for Eclipse is 0.8.0. If you are using a previous version of ADT, you should update to the latest version for use with this SDK. For information about how to update your ADT plugin, see Upgrading the SDK.

      +href="{@docRoot}sdk/1.0_r2/upgrading.html">Upgrading the SDK.

      Installation and Upgrade Notes

      If you're installing the Android SDK for the first time, please see the -instructions in Installing the +instructions in Installing the SDK.

      Other Notes

      @@ -180,8 +381,8 @@ MapView for authentication to the server.

      Developers should note that the registration service for MapView is now active and Google Maps is actively enforcing the Maps API Key requirement. For information about how to register for a Maps API Key, see http://code. -google.com/android/toolbox/apis/mapkey.html.

      +href="http://code.google.com/android/add-ons/google-apis/mapkey.html">http://code.google.com/android/add-ons/google-apis/mapkey.html. +

      USB Driver for Windows

      If you using Windows and want to develop or test your application on an @@ -206,7 +407,7 @@ do so, declare a custom resource element using a file, then declare the attribute inside. For examples, see <sdk>/samples/ApiDemos/res/values/attrs.xml. For more information about custom resources, see Custom +href="{@docRoot}guide/topics/resources/available-resources.html#customresources">Custom Layout Resources. Note that the android.R.styleable documentation is still provided in the SDK, but only as a reference of the platform's styleable attributes for the various elements. @@ -236,27 +437,27 @@ to this release.

      This SDK release is the first to include the Android 1.0 platform and application API. Applications developed on this SDK will be compatible with mobile devices running the Android 1.0 platform, when such devices are available.

      -

      This release includes mainly bug fixes, although some smaller features were added. The Android 1.0 also includes several API changes from the 0.9 version. For more information on API changes, see the Overview of Changes and the API Differences Report. For those porting from the M5 release, the SDK also includes the legacy changes overview and API Differences Reports. See the current Overview of Changes for more information.

      +

      This release includes mainly bug fixes, although some smaller features were added. The Android 1.0 also includes several API changes from the 0.9 version. For those porting from the M5 release, the SDK also includes the legacy changes overview and API Differences Reports. See the current Overview of Changes for more information.

      ADT Plugin Compatibility

      -

      For this version of the SDK — Android 1.0 SDK, Release 1 — the compatible version of the Android Development Tools (ADT) Plugin for Eclipse is 0.8.0. If you are using a previous version of ADT, you should update to the latest version for use with this SDK. For information about how to update your ADT plugin, see Upgrading the SDK.

      +

      For this version of the SDK — Android 1.0 SDK, Release 1 — the compatible version of the Android Development Tools (ADT) Plugin for Eclipse is 0.8.0. If you are using a previous version of ADT, you should update to the latest version for use with this SDK. For information about how to update your ADT plugin, see Upgrading the SDK.

      Installation and Upgrade Notes

      -

      If you've been developing an application using a previous SDK version and you want the application to run on Android-powered mobile devices, you must port the application to the Android 1.0 SDK. Please see Upgrading the SDK for detailed instructions on how to make the transition to this release. Be sure to wipe application user data (emulator option -wipe-data) when running your application on the Android 1.0 SDK emulator.

      +

      If you've been developing an application using a previous SDK version and you want the application to run on Android-powered mobile devices, you must port the application to the Android 1.0 SDK. Please see Upgrading the SDK for detailed instructions on how to make the transition to this release. Be sure to wipe application user data (emulator option -wipe-data) when running your application on the Android 1.0 SDK emulator.

      -

      If you're installing the Android SDK for the first time, please see the instructions in Installing the SDK. +

      If you're installing the Android SDK for the first time, please see the instructions in Installing the SDK.

      Other Notes

      MapView API Key

      -

      MapView is a class that lets you easily integrate Google Maps into your application. Before you can access the maps data, you will need to register with the Google Maps service and receive a Maps API Key, which you then add to your MapView for authentication to the server.

      +

      MapView is a class that lets you easily integrate Google Maps into your application. Before you can access the maps data, you will need to register with the Google Maps service and receive a Maps API Key, which you then add to your MapView for authentication to the server.

      Currently, the registration service for MapView is not yet active and Google Maps is not yet enforcing the Maps API Key requirement. However, note that the registration service will be activated soon, so that MapViews in any application deployed to a mobile device will require registration and a valid Maps API Key.

      -

      As soon as the registration service becomes available, we will update the page at http://code.google.com/android/toolbox/apis/mapkey.html with details about how and where to register. Please check that page periodically for registration information, if you are using a MapView.

      +

      As soon as the registration service becomes available, we will update the page at http://code.google.com/android/add-ons/google-apis/mapkey.html with details about how and where to register. Please check that page periodically for registration information, if you are using a MapView.

      Resolved Issues, Changes

      @@ -284,18 +485,6 @@ to this release.

    16. SQLite is now included in the SDK package on all platforms.
    17. -

      Known Issues

      - -

      JUnit and Eclipse/ADT

      -
        -
      • If you are developing in Eclipse/ADT and want to add JUnit test -classes, you can do so. However, you need to set up a custom JUnit configuration -before your tests will run properly. For detailed information about how to set -up the JUnit configuration, see the troubleshooting topic Running a Junit test class -in Eclipse.
      • -
      -

      Other

        diff --git a/docs/html/sdk/adt_download.jd b/docs/html/sdk/adt_download.jd index 6e9eec4a2b73617c2ab7099e0eb0b9e2f7615aca..8b22e2c15ebb23f255d4f3760588ddb4ec5d1ed7 100644 --- a/docs/html/sdk/adt_download.jd +++ b/docs/html/sdk/adt_download.jd @@ -8,7 +8,7 @@ update site in Eclipse, you can download the ADT zip file and install it from your computer (archived site) instead.

        -If you go with this method, in order to update the plugin, you will need to +If you use this approach, in order to update the plugin, you will need to download the latest version from this page, uninstall the old version from Eclipse, then install the new version. For more details on the procedure, see Troubleshooting ADT Installation in the @@ -16,50 +16,60 @@ see Troubleshooting ADT Installation in the page.

        - +
        - - - - + + + + - - - - - + + + + + + + + + + + +
        VersionFileDateCompatible SDK VersionsADT VersionPackageSizeMd5 Checksum Notes
        0.8.0ADT-0.8.0.zip23 September 2008Android 1.1 SDK, Release 1
        Android 1.0 SDK, Release 1
        Required for users of Android 1.1 SDK, Release 1 and Android 1.0 SDK, Release 1
        0.9.1ADT-0.9.1.zip2916093 bytese7b2ab40414ac98Required for users of Android 1.5 SDK (and later releases). Updated from 0.9.0. 6 May 2009
        0.8.0ADT-0.8.0.zip Required for users of Android 1.1 SDK and Android 1.0 SDK. 23 Sep 2008
        + + +

        Older Versions of ADT

        + +

        The table below lists older versions of the ADT Plugin that are no longer supported. If you are developing applications that are intended to be deployable to Android-powered devices, make sure that you upgrade to the most current SDK release available and use the most current version of the ADT Plugin, as listed in the section above.

        + +

        If you are not sure what version of ADT is installed in your Eclipse environment, open Eclipse and from the main menu select Help > About Eclipse > Features Details. Locate "com.android.ide.eclipse.adt" in the +Feature ID column and look at its version number.

        + + + + + + + - - - + Please upgrade to Eclipse Ganymede (3.4) or Europa (3.3) if you are still using 3.2. 18 Aug 2008 - - - - + - - - - + - - - - +
        ADT VersionNotes
        0.7.1ADT-0.7.1.zip18 Aug 2008Android 0.9 SDK beta Required for users of Android 0.9 SDK beta. As of this version, Eclipse 3.2 is no longer supported. - Please upgrade to Eclipse Ganymede (3.4) or Europa (3.3) if you are still using 3.2.
        0.4.0ADT-0.4.0.zip12 Feb 2008m5-rc14Required if you are using the M5 SDK. See the SDK Release Notes for details on changes and enhancements in this version.Required if you are using the M5 SDK. See the SDK Release Notes for details on changes and enhancements in this version. 12 Feb 2008
        0.3.3ADT-0.3.3.zip14 Dec 2007m3-rc37Some significant enhancements (see SDK Release Notes).Some significant enhancements (see m3-rc37 SDK Release Notes). 14 Dec 2007
        0.3.1ADT-0.3.1.zip21 Nov 2007m3-rc20, m3-rc22Initial Release.Initial Release. Required for Android m3-rc20 SDK and Android m3-rc22 SDK.21 Nov 2007

        diff --git a/docs/html/sdk/android-1.1.jd b/docs/html/sdk/android-1.1.jd index ce75e60fdee62b999d84210244c4242680affe07..8123fa8dad0ec744c52a5bfd1c859649bb68b1ad 100644 --- a/docs/html/sdk/android-1.1.jd +++ b/docs/html/sdk/android-1.1.jd @@ -35,17 +35,17 @@ system to correctly determine whether an application is compatible with the system, prior to installing the application.

        Applications indicate the lowest system API Level that they are compatible with by adding -a value to the minSdkVersion attribute. +a value to the android:minSdkVersion attribute. The value of the attribute is an integer corresponding to an API Level identifier. Prior to installing an application, the system checks the value of -minSdkVersion and allows the install only +android:minSdkVersion and allows the install only if the referenced integer is less than or equal to the API Level integer stored in the system itself.

        If you use the Android 1.1 system image to build an application compatible with Android-powered devices running the Android 1.1 platform, you must set the -minSdkVersion attribute to "2" in order to specify that your application +android:minSdkVersion attribute to "2" in order to specify that your application is compatible only with devices using the Android 1.1 (or greater) system image.

        @@ -68,14 +68,14 @@ your application will function properly on their devices, especially if it uses APIs introduced in Android 1.1.

        If your application uses APIs introduced in Android 1.1 but does not -declare <uses-sdk minSdkVersion="2" />, then it will +declare <uses-sdk android:minSdkVersion="2" />, then it will run properly on Android 1.1 devices but not on Android 1.0 devices. In the latter case, the application will crash at runtime when it tries to use the Android 1.1 APIs.

        If your application does not use any new APIs introduced in Android 1.1, you can indicate Android 1.0 compatibility by removing -minSdkVersion or setting the attribute to "1". However, +android:minSdkVersion or setting the attribute to "1". However, before publishing your application, you must make sure to compile your application against the Android 1.0 system image (available in the Android 1.0 SDK), to ensure that it builds and functions properly for diff --git a/docs/html/sdk/android-1.5-highlights.jd b/docs/html/sdk/android-1.5-highlights.jd new file mode 100644 index 0000000000000000000000000000000000000000..e6c4f88e4d3227af8490decdfc84c4e8d472f52d --- /dev/null +++ b/docs/html/sdk/android-1.5-highlights.jd @@ -0,0 +1,209 @@ +page.title=Android 1.5 Platform Highlights +sdk.version=1.5_r1 +@jd:body + +

        +April 2009 +

        + + +

        The Android 1.5 platform introduces many new features for users and developers. +The list below provides an overview of the changes.

        + + + +

        User Interface Refinements

        +
          +
        • System-wide: +
            +
          • Refinement of all core UI elements
          • +
          • Animated window transitions (off by default)
          • +
          • Accelerometer-based application rotations
          • +
          +
        • +
        • UI polish for: +
            +
          • In-call experience
          • +
          • Contacts, Call log, and Favorites
          • +
          • SMS & MMS
          • +
          • Browser
          • +
          • Gmail
          • +
          • Calendar
          • +
          • Email
          • +
          • Camera & Gallery
          • +
          • Application management
          • +
          +
        • +
        + +

        Performance Improvements

        + +
          +
        • Faster Camera start-up and image capture
        • +
        • Much faster acquisition of GPS location (powered by SUPL AGPS)
        • +
        • Smoother page scrolling in Browser
        • +
        • Speedier GMail conversation list scrolling
        • +
        + +

        New Features

        + +
          +
        • On-screen soft keyboard +
            +
          • Works in both portrait and landscape orientation
          • +
          • Support for user installation of 3rd party keyboards
          • +
          • User dictionary for custom words
          • +
          +
        • + +
        • Home screen +
            +
          • Widgets +
              +
            • Bundled home screen widgets include: analog clock, calendar, + music player, picture frame, and search
            • +
          • +
          • Live folders
          • +
          +
        • + +
        • Camera & Gallery +
            +
          • Video recording
          • +
          • Video playback (MPEG-4 & 3GP formats)
          • +
          +
        • + +
        • Bluetooth  +
            +
          • Stereo Bluetooth support (A2DP and AVCRP profiles)
          • +
          • Auto-pairing
          • +
          • Improved handsfree experience
          • +
          +
        • + +
        • Browser +
            +
          • Updated with latest Webkit browser & Squirrelfish Javascript engines
          • +
          • Copy 'n paste in browser
          • +
          • Search within a page
          • +
          • User-selectable text-encoding
          • +
          • UI changes include: +
              +
            • Unified Go and Search box
            • +
            • Tabbed bookmarks/history/most-visited screen
            • +
            +
          • +
          +
        • + +
        • Contacts +
            +
          • Shows user picture for Favorites
          • +
          • Specific date/time stamp for events in call log
          • +
          • One-touch access to a contact card from call log event
          • +
          +
        • + +
        • System +
            +
          • New Linux kernel (version 2.6.27)
          • +
          • SD card filesystem auto-checking and repair
          • +
          • SIM Application Toolkit 1.0
          • +
          +
        • + +
        • Google applications (not available in the Android 1.5 System Image that is +included in the Android SDK) +
            +
          • View Google Talk friends' status in Contacts, SMS, MMS, GMail, and + Email applications
          • +
          • Batch actions such as archive, delete, and label on Gmail messages
          • +
          • Upload videos to Youtube
          • +
          • Upload photos on Picasa
          • +
          +
        • +
        + +

        New APIs and Manifest Elements

        + +
          +
        • UI framework +
            +
          • Framework for easier background/UI thread interaction
          • +
          • New {@link android.widget.SlidingDrawer SlidingDrawer} widget
          • +
          • New {@link android.widget.HorizontalScrollView HorizontalScrollview} widget
          • +
          +
        • + +
        • AppWidget framework +
            +
          • APIs for creating secure home screen {@link android.appwidget +AppWidgets}. For information about how to use AppWidgets, see the Developer's +Guide AppWidgets +documentation. Also see +Introducing home screen widgets and the AppWidget +framework on the Android Developer's Blog.
          • +
          • APIs for populating {@link android.provider.LiveFolders Live Folders} + with custom content.
          • +
          +
        • + +
        • Media framework +
            +
          • Raw audio recording and playback APIs
          • +
          • Interactive MIDI playback engine
          • +
          • {@link android.media.MediaRecorder Video Recording APIs} for developers (3GP format).
          • +
          • Video and photo sharing Intents
          • +
          • Media search Intent
          • +
          +
        • + +
        • Input Method framework +
            +
          • {@link android.inputmethodservice.InputMethodService Input Method + Service} framework
          • +
          • Text-prediction engine
          • +
          • Ability to provide downloadable IMEs to users
          • +
          +
        • + +
        • Application-defined hardware requirements +

          Applications can now use a new element in their manifest files, <uses- +configuration> to indicate to the Android system what hardware features +they require in order to function properly. For example, an application might +use the element to specify that it requires a physical keyboard or a particular +navigation device, such as a trackball. Prior to installing the application, the +Android system checks the attributes defined for the +<uses-configuration> element and allows the installation to +continue only if the required hardware is present.

          +
        • + +
        • Speech recognition framework +
            +
          • Support for using speech recognition libraries via Intent. See {@link +android.speech.RecognizerIntent RecognizerIntent}.
          • +
          +
        • + +
        • Miscellaneous API additions +
            +
          • LocationManager - Applications can get location change updates via + Intent
          • +
          • WebView - Touch start/end/move/cancel DOM event support
          • +
          • Redesigned {@link android.hardware.SensorManager Sensor Manager + APIs}
          • +
          • GLSurfaceView - convenience framework for creating OpenGL + applications
          • +
          • Broadcast Intent for app update install succeeded - for smoother app + upgrade experience
          • +
          +
        • +
        diff --git a/docs/html/sdk/android-1.5.jd b/docs/html/sdk/android-1.5.jd index fff911e29096c3a76b064a7f6fc460231c01dae9..addd64465fb6d4267b949f50b16a244b1aacfc77 100644 --- a/docs/html/sdk/android-1.5.jd +++ b/docs/html/sdk/android-1.5.jd @@ -8,7 +8,268 @@ sys.date=April 2009 API Level: 3

        -

        Please see Download the Android 1.5 Early Look SDK for more information.

        +

        This document provides version notes for the Android 1.5 system image included in the SDK.

        + + + +

        Overview

        + +

        The Android 1.5 system delivered in the SDK (as library and system image) is +the development counterpart to the Android 1.5 production system image, +deployable to Android-powered handsets starting in May 2009. The system is fully +compliant and includes no external libraries. This is the first version of the +Android SDK that does not include the Maps external library.

        + +

        The Android 1.5 system delivers an updated version of the framework +API. As with previous versions, the Android 1.5 API +is assigned an integer identifier — 3 — that is +stored in the system itself. This identifier, called the "API Level", allows the +system to correctly determine whether an application is compatible with +the system, prior to installing the application.

        + +

        Applications can reference a specific API Level value in their +manifest files, to indicate the minimum version of the Android system +required to run the application. To reference a minimum API Level, applications +can add an android:minSdkVersion attribute in their manifest files. +The value of the attribute is an integer corresponding to an API Level +identifier. Prior to installing an application, the system then checks the value of +android:minSdkVersion and allows the install only +if the referenced integer is less than or equal to the API Level integer stored +in the system itself.

        + +

        When you migrate your application to the new SDK, you will need to choose +the platform version against which you will compile your application. In +general, you should compile your application against the lowest possible +version of the platform that your application can support. After you determine +the lowest version, you should ensure that your application's manifest file +defines the API Level of the lowest compatible platform version in the +android:minSdkVersion attribute. + +

        After compiling your application, you should make sure to test it on the +platform specified in the application's android:minSdkVersion attribute. To +ensure forward-compatibility, you should also run the application on platforms +using a higher API Level than that used by your application. To run your +application against different platform versions in the emulator, you create an +AVD for each platform version that you want to test. For more information about +AVDs, see Android Virtual +Devices. If you are using a physical device for testing, ensure that you +know the API Level of the Android platform it runs.

        + +

        If you build an application using the Android 1.5 library and your +application makes use of any APIs introduced in API Level 3, you must set the +android:minSdkVersion attribute in the application's manifest to +"3".

        + +

        Specifically, you define the android:minSdkVersion +attribute in a <uses-sdk> element as a child of +<manifest> in the manifest file. When set, the +attribute looks like this:

        + +
        <manifest>
        +  ...
        +  <uses-sdk android:minSdkVersion="3" />
        +  ...
        +</manifest>
        + +

        By setting android:minSdkVersion in this way, you ensure that +users will only be able to install your application if their devices are running +a compatible version of the Android platform. In turn, this ensures that your +application will function properly on their devices. This is especially +important if your application uses APIs or system features +introduced in Android 1.5.

        + +

        If your application uses APIs introduced in Android 1.5 but does not +declare <uses-sdk android:minSdkVersion="3" />, then it will +run properly on Android 1.5 devices but not on Android 1.0 +devices. In the latter case, the application will crash at runtime when +it tries to use the Android 1.5 APIs.

        + +

        Conversely, if your application does not use any new APIs introduced in +Android 1.5, the application will in most cases function normally on devices +running a later version of the platform. However, if you have published +the application, you are strongly encouraged to install and test your +application on the Android 1.5 system image included in the SDK. This will +ensure a smooth transition for users, as they upgrade their devices to +the new version of the Android platform.

        + +

        Finally, if your application does not use any new APIs introduced since +Android 1.1, you can indicate general Android 1.1 compatibility by +setting the attribute to "2". If your application does not use any +new APIs introduced since Android 1.0, you can remove the attribute or +set it to "1". However, +before publishing your application, you must make sure to compile your +application against the Android library that corresponds to the application's +android:minSdkVeresion value.

        + +

        Built-in Applications

        + +

        The system image includes these built-in applications:

        +
          +
        • Alarm Clock
        • +
        • Browser
        • +
        • Calculator
        • +
        • Camcorder
        • +
        • Camera
        • +
        • Contacts
        • +
        • Custom Locale (developer app)
        • +
        • Dev Tools (developer app)
        • +
        • Dialer
        • +
        • Email
        • +
        • Gallery
        • +
        • Messaging
        • +
        • Music
        • +
        • Settings
        • +
        • Spare Parts (developer app)
        • +
        + +

        Locales

        + +

        The system image provides a variety of built-in locales. In some cases, +region-specific strings are available for the locales. In other cases, +a default version of the language is used. The languages that will be +available in the Android 1.5 system image are listed below (with +language_country/region locale descriptor).

        + + + + + + +
        +
          +
        • Chinese, PRC (zh_CN)
        • +
        • Chinese, Taiwan (zh_TW)
        • +
        • Czech (cs_CZ)
        • +
        • Dutch, Netherlands (nl_NL)
        • +
        • Dutch, Belgium (nl_BE)
        • +
        • English, US (en_US)
        • +
        • English, Britain (en_GB)
        • +
        • English, Canada(en_CA)
        • +
        • English, Australia (en_AU)
        • +
        • English, New Zealand (en_NZ)
        • +
        • English, Singapore(en_SG)
        • +
        • French, France (fr_FR)
        • +
        • French, Belgium (fr_BE)
        • +
        +
        +
      • French, Canada (fr_CA)
      • +
      • French, Switzerland (fr_CH)
      • +
      • German, Germany (de_DE)
      • +
      • German, Austria(de_AT)
      • +
      • German, Switzerland (de_CH)
      • +
      • German, Liechtenstein (de_LI)
      • +
      • Italian, Italy (it_IT)
      • +
      • Italian, Switzerland (it_CH)
      • +
      • Japanese (ja_JP)
      • +
      • Korean (ko_KR)
      • +
      • Polish (pl_PL)
      • +
      • Russian (ru_RU)
      • +
      • Spanish (es_ES)
      • +
        + +

        Localized UI strings match the locales that are displayable in +the emulator, accessible through the device Settings application.

        + +

        New Features

        + +

        For a list of new system features, see the Android 1.5 Platform +Highlights document.

        + +

        API Changes

        + +

        Overview

        + +
          +
        • UI framework
        • +
            +
          • Framework for easier background/UI thread interaction
          • +
          • New {@link android.widget.SlidingDrawer SlidingDrawer} widget
          • +
          • New {@link android.widget.HorizontalScrollView HorizontalScrollview} widget
          • +
          + + +
        • AppWidget framework +
            +
          • APIs for creating secure home screen {@link android.appwidget +AppWidgets}. For information about how to use AppWidgets, see the Developer's +Guide AppWidgets +documentation. Also see +Introducing home screen widgets and the AppWidget +framework on the Android Developer's Blog.
          • +
          • APIs for populating {@link android.provider.LiveFolders Live Folders} + with custom content.
          • +
          +
        • + +
        • Media framework
        • +
            +
          • Raw audio recording and playback APIs
          • +
          • Interactive MIDI playback engine
          • +
          • Video recording APIs for developers (3GP format)
          • +
          • Video and photo sharing Intents
          • +
          • Media search Intent
          • +
          + + +
        • Input Method framework +
            +
          • {@link android.inputmethodservice.InputMethodService Input Method + Service} framework
          • +
          • Text-prediction engine
          • +
          • Ability to provide downloadable IMEs to users
          • +
          +
        • + +
        • Application-defined hardware requirements +

          Applications can now use a new element in their manifest files, <uses- +configuration> to indicate to the Android system what hardware features +they require in order to function properly. For example, an application might +use the element to specify that it requires a physical keyboard or a particular +navigation device, such as a trackball. Prior to installing the application, the +Android system checks the attributes defined for the +<uses-configuration> element and allows the installation to +continue only if the required hardware is present.

          +
        • + +
        • Speech recognition framework +
            +
          • Support for using speech recognition libraries via Intent. See {@link +android.speech.RecognizerIntent RecognizerIntent}.
          • +
          +
        • + +
        • Miscellaneous API additions +
            +
          • LocationManager - Applications can get location change updates via + Intent
          • +
          • WebView - Touch start/end/move/cancel DOM event support
          • +
          • Redesigned {@link android.hardware.SensorManager Sensor Manager + APIs}
          • +
          • GLSurfaceView - convenience framework for creating OpenGL + applications
          • +
          • Broadcast Intent for app update install succeeded - for smoother app + upgrade experience
          • +
          +
        • + +
        + +

        API Change Details

        + +

        For a detailed view of API changes in this platform (API Level 3), see the API Differences Report.

        diff --git a/docs/html/sdk/api_diff/3/changes.html b/docs/html/sdk/api_diff/3/changes.html new file mode 100644 index 0000000000000000000000000000000000000000..bc0f8791013c15323d36c2da8e2c5d314e9ef513 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes.html @@ -0,0 +1,46 @@ + + + + + + + + + + +API Differences between 2 and 3 + + + + + + + + + + + + + + +<H2> +Frame Alert +</H2> + +<P> +This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +<BR> +Link to <A HREF="changes/changes-summary.html" target="_top">Non-frame version.</A> + + diff --git a/docs/html/sdk/api_diff/3/changes/alldiffs_index_additions.html b/docs/html/sdk/api_diff/3/changes/alldiffs_index_additions.html new file mode 100644 index 0000000000000000000000000000000000000000..41f78ab79d971fba377ebfccd861fc1600fea810 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/alldiffs_index_additions.html @@ -0,0 +1,3144 @@ + + + + + + + + + +All Additions Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Differences +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + + +
        A  +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +AbsoluteSizeSpan +(Parcel) constructor
        + +ACCELEROMETER_ROTATION +
        + +ACTION_AIRPLANE_MODE_SETTINGS +
        + +ACTION_APPLICATION_DEVELOPMENT_SETTINGS +
        + +ACTION_AUDIO_BECOMING_NOISY +
        + +ACTION_BACKGROUND_DATA_SETTING_CHANGED +
        + +ACTION_DATA_ROAMING_SETTINGS +
        + +ACTION_IMAGE_CAPTURE +
        + +ACTION_INPUT_METHOD_CHANGED +
        + +ACTION_INPUT_METHOD_SETTINGS +
        + +ACTION_INTERNAL_STORAGE_SETTINGS +
        + +ACTION_MANAGE_APPLICATIONS_SETTINGS +
        + +ACTION_MEDIA_CHECKING +
        + +ACTION_MEDIA_NOFS +
        + +ACTION_MEMORY_CARD_SETTINGS +
        + +ACTION_NETWORK_OPERATOR_SETTINGS +
        + +ACTION_OUTSIDE +
        + +ACTION_PACKAGE_DATA_CLEARED +
        + +ACTION_PACKAGE_REPLACED +
        + +ACTION_PHONE_STATE_CHANGED +
        + +ACTION_QUICK_LAUNCH_SETTINGS +
        + +ACTION_SEARCH_LONG_PRESS +
        + +ACTION_SYNC_SETTINGS +
        + +ACTION_SYSTEM_TUTORIAL +
        + +ACTION_USER_DICTIONARY_SETTINGS +
        + +ACTION_USER_PRESENT +
        + +ACTION_VIDEO_CAPTURE +
        + +ACTION_WIFI_IP_SETTINGS +
        + +ActivityInstrumentationTestCase2
        + +ActivityManager.RunningAppProcessInfo
        + +addGpsStatusListener +(Listener)
        + +addOnScrollChangedListener +(OnScrollChangedListener)
        + +addPropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        + +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        + +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        + +addTestProvider +(String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int)
        + +addToDictionary +
        + +adjustMetaAfterKeypress +(long)
        + +ALIGN_BASELINE +
        + +ALIGN_BOTTOM +
        + +AlignmentSpan.Standard +(Parcel) constructor
        + +allowSingleTap +
        + +AlphabetIndexer
        + +android.appwidget
        + +android.inputmethodservice
        + +android.speech
        + +android.text.format
        + +android.view.inputmethod
        + +animateOnClick +
        + +Annotation +(Parcel) constructor
        + +applyDisplay +(int, Rect, Rect)
        + +AssetFileDescriptor.AutoCloseInputStream
        + +AssetFileDescriptor.AutoCloseOutputStream
        + +AsyncTask
        + +AsyncTask.Status
        + +AudioFormat
        + +AudioRecord
        + +AudioRecord.OnRecordPositionUpdateListener
        + +AudioTrack
        + +AudioTrack.OnPlaybackPositionUpdateListener
        + +AXIS_CLIP +
        + +AXIS_MINUS_X +
        + +AXIS_MINUS_Y +
        + +AXIS_MINUS_Z +
        + +AXIS_X +
        + +AXIS_Y +
        + +AXIS_Z +
        + + +
        B  +A +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +BackgroundColorSpan +(Parcel) constructor
        + +backgroundDimEnabled +
        + +beginBatchEdit +()
        + +BIND_APPWIDGET +
        + +BIND_INPUT_METHOD +
        + +BOOKMARK +
        + +bottomOffset +
        + +bringPointIntoView +(int)
        + +BUCKET_DISPLAY_NAME +
        + +BUCKET_ID +
        + +BulletSpan +(Parcel) constructor
        + +BUTTON_NEGATIVE +
        + +BUTTON_NEUTRAL +
        + +BUTTON_POSITIVE +
        + + +
        C  +A +B +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +calculateLength +(CharSequence, boolean)
        + +callActivityOnUserLeaving +(Activity)
        + +candidatesArea +
        + +candidatesTextStyleSpans +
        + +CAP_MODE_CHARACTERS +
        + +CAP_MODE_SENTENCES +
        + +CAP_MODE_WORDS +
        + +CATEGORY_INFO +
        + +changeAction +(KeyEvent, int)
        + +changeCursorAndColumns +(Cursor, String[], int[])
        + +changeFlags +(KeyEvent, int)
        + +changeTimeRepeat +(KeyEvent, long, int)
        + +checkInputConnectionProxy +(View)
        + +Chronometer.OnChronometerTickListener
        + +clearComposingText +()
        + +clearListSelection +()
        + +clearMatches +()
        + +clearMetaKeyState
        +  type  +(View, Editable, int) in android.text.method.KeyListener +
        + +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        + +  type  +(View, Editable, int) in android.text.method.MetaKeyKeyListener +
        + +  type  +(Editable, int) in android.text.method.MetaKeyKeyListener +
        + +clearTestProviderEnabled +(String)
        + +clearTestProviderLocation +(String)
        + +clearTestProviderStatus +(String)
        + +CLIP_HORIZONTAL +
        + +CLIP_VERTICAL +
        + +close +()
        + +closeButton +
        + +closeContextMenu +()
        + +codes +
        + +computeDurationHint +()
        + +configPreferences +
        + +ConfigurationInfo
        + +configure +
        + +content +
        + +copy +
        + +copyPixelsFromBuffer +(Buffer)
        + +copyUrl +
        + +createInputStream +()
        + +createOutputStream +()
        + +createWifiLock +(int, String)
        + +CREATOR
        + in  +android.content.res.AssetFileDescriptor +
        + + in  +android.graphics.RectF +
        + +cut +
        + + +
        D  +A +B +C +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +dark_header +
        + +DEBUG_ENABLE_ASSERT +
        + +DEBUG_ENABLE_CHECKJNI +
        + +DEBUG_ENABLE_DEBUGGER +
        + +describeContents
        +  type  +() in android.content.res.AssetFileDescriptor +
        + +  type  +() in android.graphics.RectF +
        + +  type  +() in android.text.Annotation +
        + +  type  +() in android.text.style.AbsoluteSizeSpan +
        + +  type  +() in android.text.style.AlignmentSpan.Standard +
        + +  type  +() in android.text.style.BackgroundColorSpan +
        + +  type  +() in android.text.style.BulletSpan +
        + +  type  +() in android.text.style.ForegroundColorSpan +
        + +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        + +  type  +() in android.text.style.QuoteSpan +
        + +  type  +() in android.text.style.RelativeSizeSpan +
        + +  type  +() in android.text.style.ScaleXSpan +
        + +  type  +() in android.text.style.StrikethroughSpan +
        + +  type  +() in android.text.style.StyleSpan +
        + +  type  +() in android.text.style.SubscriptSpan +
        + +  type  +() in android.text.style.SuperscriptSpan +
        + +  type  +() in android.text.style.TextAppearanceSpan +
        + +  type  +() in android.text.style.TypefaceSpan +
        + +  type  +() in android.text.style.URLSpan +
        + +  type  +() in android.text.style.UnderlineSpan +
        + +deviceHasKey +(int)
        + +deviceHasKeys +(int[])
        + +DexClassLoader
        + +dialog_alert_title +
        + +didTouchFocusSelect +()
        + +dispatchKeyEventPreIme +(KeyEvent)
        + +DISPLAY +
        + +DISPLAY_CLIP_HORIZONTAL +
        + +DISPLAY_CLIP_VERTICAL +
        + +drag +(InstrumentationTestCase, float, float, float, float, int)
        + +dragQuarterScreenDown +(InstrumentationTestCase, Activity)
        + +dragQuarterScreenUp +(InstrumentationTestCase, Activity)
        + +dragViewBy +(InstrumentationTestCase, View, int, int, int)
        + +dragViewTo +(InstrumentationTestCase, View, int, int, int)
        + +dragViewToBottom
        +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        + +  type  +(InstrumentationTestCase, Activity, View, int) in android.test.TouchUtils +
        + +dragViewToTop
        +  type  +(InstrumentationTestCase, View) in android.test.TouchUtils +
        + +  type  +(InstrumentationTestCase, View, int) in android.test.TouchUtils +
        + +dragViewToX +(InstrumentationTestCase, View, int, int)
        + +dragViewToY +(InstrumentationTestCase, View, int, int)
        + +drawBitmap +(int[], int, int, float, float, int, int, boolean, Paint)
        + +dropDownAnchor +
        + +dropDownWidth +
        + +dump
        +  type  +(Printer, String) in android.location.Location +
        + +  type  +(FileDescriptor, String[]) in android.os.Binder +
        + +  type  +(FileDescriptor, String[]) in android.os.IBinder +
        + +dumpCapturedView +(String, Object)
        + +dumpHprofData
        +  type  +(String) in android.os.Debug +
        + +  type  +(String) in dalvik.system.VMDebug +
        + +dumpSpans +(CharSequence, Printer, String)
        + +DynamicDrawableSpan +(int) constructor
        + + +
        E  +A +B +C +D +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +editorExtras +
        + +endBatchEdit +()
        + +EXTRA_APPLICATION_ID +
        + +EXTRA_CREATE_DESCRIPTION +
        + +EXTRA_DATA_REMOVED +
        + +EXTRA_FINISH_ON_COMPLETION +
        + +EXTRA_FORCE_CREATE +
        + +EXTRA_INCOMING_NUMBER +
        + +EXTRA_MAX_BYTES +
        + +EXTRA_MEDIA_ALBUM +
        + +EXTRA_MEDIA_ARTIST +
        + +EXTRA_MEDIA_FOCUS +
        + +EXTRA_MEDIA_TITLE +
        + +EXTRA_OUTPUT +
        + +EXTRA_REPLACING +
        + +EXTRA_SCREEN_ORIENTATION +
        + +EXTRA_STATE +
        + +EXTRA_STATE_IDLE +
        + +EXTRA_STATE_OFFHOOK +
        + +EXTRA_STATE_RINGING +
        + +EXTRA_VIDEO_QUALITY +
        + +extractArea +
        + +extractText +(ExtractedTextRequest, ExtractedText)
        + + +
        F  +A +B +C +D +E +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +fastScrollEnabled +
        + +fillEnabled +
        + +findAll +(String)
        + +findNext +(boolean)
        + +FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET +
        + +FLAG_ACTIVITY_NO_USER_ACTION +
        + +FLAG_ACTIVITY_REORDER_TO_FRONT +
        + +FLAG_ALT_FOCUSABLE_IM +
        + +FLAG_EDITOR_ACTION +
        + +FLAG_FROM_SYSTEM +
        + +FLAG_KEEP_TOUCH_MODE +
        + +FLAG_NO_HISTORY +
        + +FLAG_SOFT_KEYBOARD +
        + +FLAG_UPDATE_CURRENT +
        + +FLAG_WATCH_OUTSIDE_TOUCH +
        + +footerDividersEnabled +
        + +ForegroundColorSpan +(Parcel) constructor
        + +forkAndSpecialize +(int, int, int[], int, int[][])
        + +forkSystemServer +(int, int, int[], int, int[][])
        + +FORMAT_JAPAN +
        + +formatJapaneseNumber +(Editable)
        + +FX_KEYPRESS_DELETE +
        + +FX_KEYPRESS_RETURN +
        + +FX_KEYPRESS_SPACEBAR +
        + +FX_KEYPRESS_STANDARD +
        + + +
        G  +A +B +C +D +E +F +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +GeomagneticField
        + +GestureDetector
        +  GestureDetector +(Context, OnGestureListener) constructor
        + +  GestureDetector +(Context, OnGestureListener, Handler) constructor
        + +GestureDetector.OnDoubleTapListener
        + +get +(Context)
        + +GET_CONFIGURATIONS +
        + +GET_UNINSTALLED_PACKAGES +
        + +getAllowFileAccess +()
        + +getBackgroundDataSetting +()
        + +getBoolean +(int)
        + +getBuiltInZoomControls +()
        + +getButton +(int)
        + +getCapsMode +(CharSequence, int, int)
        + +getCharacters +()
        + +getDeclaredLength +()
        + +getDefaultSensor +(int)
        + +getDeviceConfigurationInfo +()
        + +getDialog +()
        + +getDoubleTapTimeout +()
        + +getDrawable
        +  type  +() in android.graphics.drawable.RotateDrawable +
        + +  type  +() in android.graphics.drawable.ScaleDrawable +
        + +getDropDownAnchor +()
        + +getDropDownWidth +()
        + +getEditableText +()
        + +getFraction +(int, int, int)
        + +getGpsStatus +(GpsStatus)
        + +getImeActionId +()
        + +getImeActionLabel +()
        + +getImeOptions +()
        + +getInclination +(float[])
        + +getInitialScrollX +(TextView, Spannable)
        + +getInitialScrollY +(TextView, Spannable)
        + +getInputExtras +(boolean)
        + +getInputMethodMode +()
        + +getInputType
        +  type  +() in android.text.method.DateKeyListener +
        + +  type  +() in android.text.method.DateTimeKeyListener +
        + +  type  +() in android.text.method.DialerKeyListener +
        + +  type  +() in android.text.method.DigitsKeyListener +
        + +  type  +() in android.text.method.KeyListener +
        + +  type  +() in android.text.method.MultiTapKeyListener +
        + +  type  +() in android.text.method.QwertyKeyListener +
        + +  type  +() in android.text.method.TextKeyListener +
        + +  type  +() in android.text.method.TimeKeyListener +
        + +  type  +() in android.widget.TextView +
        + +getItem +(int)
        + +getKeyProgressIncrement +()
        + +getLaunchIntentForPackage
        +  type  +(String) in android.content.pm.PackageManager +
        + +  type  +(String) in android.test.mock.MockPackageManager +
        + +getLayoutDimension +(int, int)
        + +getListSelection +()
        + +getListView +()
        + +getLoggingMXBean +()
        + +getLong
        +  type  +(ContentResolver, String) in android.provider.Settings.System +
        + +  type  +(ContentResolver, String, long) in android.provider.Settings.System +
        + +getMaxAvailableHeight +(View, int)
        + +getMaxKeyCode +()
        + +getMetaState
        +  type  +(long) in android.text.method.MetaKeyKeyListener +
        + +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        + +getNeighboringCellInfo +()
        + +getOnChronometerTickListener +()
        + +getOnItemClickListener +()
        + +getOnItemSelectedListener +()
        + +getOrientation +(float[], float[])
        + +getOriginalUrl
        +  type  +() in android.webkit.WebHistoryItem +
        + +  type  +() in android.webkit.WebView +
        + +getPluginData
        +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptHandler +
        + +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptRegistry +
        + +getPrivateImeOptions +()
        + +getRotationMatrix +(float[], float[], float[], float[])
        + +getRunningAppProcesses +()
        + +getScaledDoubleTapSlop +()
        + +getScaledEdgeSlop +()
        + +getScaledFadingEdgeLength +()
        + +getScaledMaximumDrawingCacheSize +()
        + +getScaledMinimumFlingVelocity +()
        + +getScaledScrollBarSize +()
        + +getScaledTouchSlop +()
        + +getScaledWindowTouchSlop +()
        + +getSensorList +(int)
        + +getSize +(View)
        + +getSpanTypeId
        +  type  +() in android.text.Annotation +
        + +  type  +() in android.text.style.AbsoluteSizeSpan +
        + +  type  +() in android.text.style.AlignmentSpan.Standard +
        + +  type  +() in android.text.style.BackgroundColorSpan +
        + +  type  +() in android.text.style.BulletSpan +
        + +  type  +() in android.text.style.ForegroundColorSpan +
        + +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        + +  type  +() in android.text.style.QuoteSpan +
        + +  type  +() in android.text.style.RelativeSizeSpan +
        + +  type  +() in android.text.style.ScaleXSpan +
        + +  type  +() in android.text.style.StrikethroughSpan +
        + +  type  +() in android.text.style.StyleSpan +
        + +  type  +() in android.text.style.SubscriptSpan +
        + +  type  +() in android.text.style.SuperscriptSpan +
        + +  type  +() in android.text.style.TextAppearanceSpan +
        + +  type  +() in android.text.style.TypefaceSpan +
        + +  type  +() in android.text.style.URLSpan +
        + +  type  +() in android.text.style.UnderlineSpan +
        + +getStartX +()
        + +getStartY +()
        + +getStatSize +()
        + +getSubtype +()
        + +getSubtypeName +()
        + +getSystemSharedLibraryNames
        +  type  +() in android.content.pm.PackageManager +
        + +  type  +() in android.test.mock.MockPackageManager +
        + +getTextFilter +()
        + +getThread +()
        + +getTimeZoneDatabaseVersion +()
        + +getUserAgentString +()
        + +getVerticalAlignment +()
        + +getWindowVisibleDisplayFrame +(Rect)
        + +GLSurfaceView
        + +GLSurfaceView.EGLConfigChooser
        + +GLSurfaceView.GLWrapper
        + +GLSurfaceView.Renderer
        + +GpsSatellite
        + +GpsStatus
        + +GpsStatus.Listener
        + + +
        H  +A +B +C +D +E +F +G +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +handle +
        + +handleKeyDown +(long, int, KeyEvent)
        + +handleKeyUp +(long, int, KeyEvent)
        + +Handler
        +  Handler +(Callback) constructor
        + +  Handler +(Looper, Callback) constructor
        + +Handler.Callback
        + +HAPTIC_FEEDBACK_ENABLED
        + in  +android.provider.Settings.System +
        + + in  +android.view.View +
        + +HapticFeedbackConstants
        + +hapticFeedbackEnabled +
        + +hardKeyboardHidden +
        + +HARDKEYBOARDHIDDEN_NO +
        + +HARDKEYBOARDHIDDEN_UNDEFINED +
        + +HARDKEYBOARDHIDDEN_YES +
        + +hasSoftInputMode +()
        + +hasWindowFocus +()
        + +headerDividersEnabled +
        + +horizontalGap +
        + +HorizontalScrollView
        + + +
        I  +A +B +C +D +E +F +G +H +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +ic_btn_speak_now +
        + +iconPreview +
        + +ImageSpan
        +  ImageSpan +(Context, Uri, int) constructor
        + +  ImageSpan +(Context, int, int) constructor
        + +  ImageSpan +(Bitmap, int) constructor
        + +  ImageSpan +(Drawable, int) constructor
        + +  ImageSpan +(Drawable, String, int) constructor
        + +imeActionId +
        + +imeActionLabel +
        + +imeExtractEnterAnimation +
        + +imeExtractExitAnimation +
        + +imeFullscreenBackground +
        + +imeOptions +
        + +inferStreamType +()
        + +initialLayout +
        + +innerRadius +
        + +INPUT_METHOD_FROM_FOCUSABLE +
        + +INPUT_METHOD_NEEDED +
        + +INPUT_METHOD_NOT_NEEDED +
        + +INPUT_METHOD_SERVICE +
        + +inputArea +
        + +inputExtractEditText +
        + +InputType
        + +inputType +
        + +INSTALL_FAILED_CONFLICTING_PROVIDER +
        + +INTENT_ACTION_MEDIA_SEARCH +
        + +INTENT_ACTION_STILL_IMAGE_CAMERA +
        + +INTENT_ACTION_VIDEO_CAMERA +
        + +intentForPosition +(int)
        + +IntentService
        + +INTERVAL_DAY +
        + +INTERVAL_FIFTEEN_MINUTES +
        + +INTERVAL_HALF_DAY +
        + +INTERVAL_HALF_HOUR +
        + +INTERVAL_HOUR +
        + +isAboveAnchor +()
        + +isBluetoothA2dpOn +()
        + +isClippingEnabled +()
        + +isDebuggingEnabled +()
        + +isDefault +
        + +isFastScrollEnabled +()
        + +isFillEnabled +()
        + +isHapticFeedbackEnabled +()
        + +isInEditMode +()
        + +isInputMethodTarget +()
        + +isLooping +()
        + +isModifier +
        + +isOutsideTouchable +()
        + +isPerformingCompletion +()
        + +isRepeatable +
        + +isRoaming +()
        + +isSafeMode
        +  type  +() in android.content.pm.PackageManager +
        + +  type  +() in android.test.mock.MockPackageManager +
        + +isScrollContainer +
        + +isSelectingMetaTracker +(CharSequence, Object)
        + +isSmoothScrollbarEnabled +()
        + +isSticky +
        + +isTouchable +()
        + + +java.beans
        + +JetPlayer
        + +JetPlayer.OnJetEventListener
        + + +
        K  +A +B +C +D +E +F +G +H +I +J +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +KEY_LOCATION_CHANGED +
        + +KEY_PROVIDER_ENABLED +
        + +KEY_STATUS_CHANGED +
        + +keyBackground +
        + +keyboardMode +
        + +keyboardView +
        + +KEYCODE_MEDIA_FAST_FORWARD +
        + +KEYCODE_MEDIA_NEXT +
        + +KEYCODE_MEDIA_PLAY_PAUSE +
        + +KEYCODE_MEDIA_PREVIOUS +
        + +KEYCODE_MEDIA_REWIND +
        + +KEYCODE_MEDIA_STOP +
        + +KEYCODE_MUTE +
        + +keyEdgeFlags +
        + +KeyEvent
        +  KeyEvent +(KeyEvent) constructor
        + +  KeyEvent +(long, String, int, int) constructor
        + +keyHeight +
        + +keyIcon +
        + +keyLabel +
        + +keyOutputText +
        + +keyPreviewHeight +
        + +keyPreviewLayout +
        + +keyPreviewOffset +
        + +keyTextColor +
        + +keyTextSize +
        + +keyWidth +
        + + +
        L  +A +B +C +D +E +F +G +H +I +J +K +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +labelTextSize +
        + +launchActivityWithIntent +(String, Class<T>, Intent)
        + +LauncherActivity.IconResizer
        + +LauncherActivity.ListItem
        + +LeadingMarginSpan.Standard +(Parcel) constructor
        + +LiveFolders
        + +load
        +  type  +(AssetFileDescriptor, int) in android.media.SoundPool +
        + +  type  +(FileDescriptor, long, long, int) in android.media.SoundPool +
        + +loadDex +(String, String, int)
        + +LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED +
        + +longClickView +(InstrumentationTestCase, View)
        + + +
        M  +A +B +C +D +E +F +G +H +I +J +K +L +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +makeListItems +()
        + +mayUseInputMethod +(int)
        + +MEDIA_CHECKING +
        + +MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK +
        + +MEDIA_INFO_BAD_INTERLEAVING +
        + +MEDIA_INFO_NOT_SEEKABLE +
        + +MEDIA_INFO_UNKNOWN +
        + +MEDIA_INFO_VIDEO_TRACK_LAGGING +
        + +MEDIA_NOFS +
        + +MEDIA_RECORDER_ERROR_UNKNOWN +
        + +MEDIA_RECORDER_INFO_MAX_DURATION_REACHED +
        + +MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED +
        + +MEDIA_RECORDER_INFO_UNKNOWN +
        + +MediaPlayer.OnInfoListener
        + +MediaPlayer.OnVideoSizeChangedListener
        + +MediaRecorder.OnErrorListener
        + +MediaRecorder.OnInfoListener
        + +MediaRecorder.VideoEncoder
        + +MediaRecorder.VideoSource
        + +MODE_APPEND +
        + +MOUNT_FORMAT_FILESYSTEMS +
        + +moveCursorToVisibleOffset +()
        + +mutate +()
        + +mVerticalAlignment +
        + + +
        N  +A +B +C +D +E +F +G +H +I +J +K +L +M +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +NeighboringCellInfo
        + +NoCopySpan
        + +NoCopySpan.Concrete
        + +noHistory +
        + +NUMBER_OF_SONGS_FOR_ARTIST +
        + + +
        O  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +P +Q +R +S +T +U +V +W +Y + TOP +

        +onBeginBatchEdit +()
        + +onCheckIsTextEditor +()
        + +onCommitCompletion +(CompletionInfo)
        + +onContentChanged +()
        + +onCreateInputConnection +(EditorInfo)
        + +onDoubleTap +(MotionEvent)
        + +onDoubleTapEvent +(MotionEvent)
        + +onEditorAction +(int)
        + +onEndBatchEdit +()
        + +onFinishTemporaryDetach +()
        + +onKeyOther
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ArrowKeyMovementMethod +
        + +  type  +(View, Editable, KeyEvent) in android.text.method.BaseKeyListener +
        + +  type  +(View, Editable, KeyEvent) in android.text.method.KeyListener +
        + +  type  +(TextView, Spannable, KeyEvent) in android.text.method.MovementMethod +
        + +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ScrollingMovementMethod +
        + +onKeyPreIme +(int, KeyEvent)
        + +onPrivateIMECommand +(String, Bundle)
        + +onSelectionChanged +(int, int)
        + +onSingleTapConfirmed +(MotionEvent)
        + +onStartTemporaryDetach +()
        + +onTextContextMenuItem +(int)
        + +onUserInteraction +()
        + +onUserLeaveHint +()
        + +openAssetFile +(Uri, String)
        + +openAssetFileDescriptor +(Uri, String)
        + +openOutputStream +(Uri, String)
        + +openRawResource +(int, TypedValue)
        + +OrientationEventListener
        + +OrientationListener +(Context, int) constructor
        + + +
        P  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +Q +R +S +T +U +V +W +Y + TOP +

        +ParcelableSpan
        + +parseBundleExtra +(String, AttributeSet, Bundle)
        + +parseBundleExtras +(XmlResourceParser, Bundle)
        + +paste +
        + +peekService +(Context, Intent)
        + +performHapticFeedback
        +  type  +(int) in android.view.View +
        + +  type  +(int, int) in android.view.View +
        + +PHONETIC_NAME
        + in  +android.provider.Contacts.Intents.Insert +
        + + in  +android.provider.Contacts.PeopleColumns +
        + +playSoundEffect +(int, float)
        + +PluginData
        + +popupCharacters +
        + +popupKeyboard +
        + +popupLayout +
        + +PrintStreamPrinter
        + +privateImeOptions +
        + +ProviderTestCase2
        + +putLong +(ContentResolver, String, long)
        + + +
        Q  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +R +S +T +U +V +W +Y + TOP +

        +QuoteSpan +(Parcel) constructor
        + + +
        R  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +S +T +U +V +W +Y + TOP +

        +R.bool
        + +R.integer
        + +RAW_AMR +
        + +readFromParcel +(Parcel)
        + +registerListener
        +  type  +(SensorEventListener, Sensor, int) in android.hardware.SensorManager +
        + +  type  +(SensorEventListener, Sensor, int, Handler) in android.hardware.SensorManager +
        + +RelativeSizeSpan +(Parcel) constructor
        + +remapCoordinateSystem +(float[], int, int, float[])
        + +RemoteViews.ActionException +(Exception) constructor
        + +removeAt +(int)
        + +removeGpsStatusListener +(Listener)
        + +removeOnScrollChangedListener +(OnScrollChangedListener)
        + +removePropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        + +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        + +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        + +removeTestProvider +(String)
        + +removeUpdates +(PendingIntent)
        + +replaceExtras
        +  type  +(Intent) in android.content.Intent +
        + +  type  +(Bundle) in android.content.Intent +
        + +reqFiveWayNav +
        + +reqHardKeyboard +
        + +reqKeyboardType +
        + +reqNavigation +
        + +reqTouchScreen +
        + +requestChildRectangleOnScreen +(View, Rect, boolean)
        + +requestLocationUpdates +(String, long, float, PendingIntent)
        + +resetLockedMeta +(long)
        + +ResourceCursorAdapter +(Context, int, Cursor, boolean) constructor
        + +restartPackage +(String)
        + +restorePicture +(Bundle, File)
        + +ResultReceiver
        + +ROUTE_BLUETOOTH_A2DP +
        + +ROUTE_BLUETOOTH_SCO +
        + +rowEdgeFlags +
        + +runTestOnUiThread +(Runnable)
        + + +
        S  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +T +U +V +W +Y + TOP +

        +savePicture +(Bundle, File)
        + +ScaleXSpan +(Parcel) constructor
        + +SCREEN_BRIGHTNESS_CHANGED +
        + +SCREEN_ORIENTATION_CHANGED +
        + +screenBrightness +
        + +screenOrientation +
        + +scrollToBottom +(InstrumentationTestCase, Activity, ViewGroup)
        + +scrollToTop +(InstrumentationTestCase, Activity, ViewGroup)
        + +SECONDARY_EMAIL +
        + +SECONDARY_EMAIL_TYPE +
        + +SECONDARY_PHONE +
        + +SECONDARY_PHONE_TYPE +
        + +SectionIndexer
        + +selectAll +
        + +sendExtraCommand +(String, String, Bundle)
        + +Sensor
        + +SensorEvent
        + +SensorEventListener
        + +setAllowFileAccess +(boolean)
        + +setBitmap +(int, String, Bitmap)
        + +setBluetoothA2dpOn +(boolean)
        + +setBoolean +(int, String, boolean)
        + +setBuiltInZoomControls +(boolean)
        + +setButton
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(CharSequence, Message) in android.app.AlertDialog +
        + +setByte +(int, String, byte)
        + +setCamera +(Camera)
        + +setChar +(int, String, char)
        + +setCharSequence +(int, String, CharSequence)
        + +setClippingEnabled +(boolean)
        + +setCompoundDrawablesWithIntrinsicBounds +(int, int, int, int)
        + +setDouble +(int, String, double)
        + +setDropDownAnchor +(int)
        + +setDropDownWidth +(int)
        + +setExtractedText +(ExtractedText)
        + +setFastScrollEnabled +(boolean)
        + +setFillEnabled +(boolean)
        + +setFloat +(int, String, float)
        + +setFooterDividersEnabled +(boolean)
        + +setHapticFeedbackEnabled +(boolean)
        + +setHeaderDividersEnabled +(boolean)
        + +setImageViewBitmap +(int, Bitmap)
        + +setImeActionLabel +(CharSequence, int)
        + +setImeOptions +(int)
        + +setInexactRepeating +(int, long, long, PendingIntent)
        + +setInputExtras +(int)
        + +setInputMethodMode +(int)
        + +setInputType +(int)
        + +setInt +(int, String, int)
        + +setKeyProgressIncrement +(int)
        + +setListSelection +(int)
        + +setLong +(int, String, long)
        + +setMaxDuration +(int)
        + +setMaxFileSize +(long)
        + +setNetworkAvailable +(boolean)
        + +setOnChronometerTickListener +(OnChronometerTickListener)
        + +setOnClickPendingIntent +(int, PendingIntent)
        + +setOnDoubleTapListener +(OnDoubleTapListener)
        + +setOnEditorActionListener +(OnEditorActionListener)
        + +setOnErrorListener +(OnErrorListener)
        + +setOneShotPreviewCallback +(PreviewCallback)
        + +setOnInfoListener
        +  type  +(OnInfoListener) in android.media.MediaPlayer +
        + +  type  +(OnInfoListener) in android.media.MediaRecorder +
        + +setOnVideoSizeChangedListener +(OnVideoSizeChangedListener)
        + +setOutputFile +(FileDescriptor)
        + +setOutsideTouchable +(boolean)
        + +setPrivateImeOptions +(String)
        + +setRawInputType +(int)
        + +setScrollContainer +(boolean)
        + +setShort +(int, String, short)
        + +setSmoothScrollbarEnabled +(boolean)
        + +setSoftInputMode +(int)
        + +setStaticTransformationsEnabled +(boolean)
        + +setString +(int, String, String)
        + +setTestProviderEnabled +(String, boolean)
        + +setTestProviderLocation +(String, Location)
        + +setTestProviderStatus +(String, int, Bundle, long)
        + +setTextColor +(int, int)
        + +Settings.Secure
        + +settingsActivity +
        + +setTouchable +(boolean)
        + +setTouchInterceptor +(OnTouchListener)
        + +setUri +(int, String, Uri)
        + +setUserAgentString +(String)
        + +setVideoEncoder +(int)
        + +setVideoFrameRate +(int)
        + +setVideoSize +(int, int)
        + +setVideoSource +(int)
        + +setView +(View, int, int, int, int)
        + +setViewResource +(int)
        + +setVisible +(boolean)
        + +setWindowAnimations +(int)
        + +setWindowLayoutMode +(int, int)
        + +sharedUserId +
        + +sharedUserLabel
        + in  +android.R.attr +
        + + in  +android.content.pm.PackageInfo +
        + +SHOW_OR_CREATE_CONTACT +
        + +SlidingDrawer
        + +SlidingDrawer.OnDrawerCloseListener
        + +SlidingDrawer.OnDrawerOpenListener
        + +SlidingDrawer.OnDrawerScrollListener
        + +smoothScrollbar +
        + +SOFT_INPUT_ADJUST_PAN +
        + +SOFT_INPUT_ADJUST_RESIZE +
        + +SOFT_INPUT_ADJUST_UNSPECIFIED +
        + +SOFT_INPUT_IS_FORWARD_NAVIGATION +
        + +SOFT_INPUT_MASK_ADJUST +
        + +SOFT_INPUT_MASK_STATE +
        + +SOFT_INPUT_MODE_CHANGED +
        + +SOFT_INPUT_STATE_ALWAYS_HIDDEN +
        + +SOFT_INPUT_STATE_ALWAYS_VISIBLE +
        + +SOFT_INPUT_STATE_HIDDEN +
        + +SOFT_INPUT_STATE_UNCHANGED +
        + +SOFT_INPUT_STATE_UNSPECIFIED +
        + +SOFT_INPUT_STATE_VISIBLE +
        + +softInputMode
        + in  +android.content.pm.ActivityInfo +
        + + in  +android.view.WindowManager.LayoutParams +
        + +sort +(Comparator<? super T>)
        + +SPAN_COMPOSING +
        + +SPAN_INTERMEDIATE +
        + +SPAN_POINT_MARK_MASK +
        + +startSelectingText +
        + +state_long_pressable +
        + +stopSelectingText +
        + +STREAM_NOTIFICATION +
        + +STRETCH_SPACING_UNIFORM +
        + +StrikethroughSpan +(Parcel) constructor
        + +StyleSpan +(Parcel) constructor
        + +SubscriptSpan +(Parcel) constructor
        + +SuperscriptSpan +(Parcel) constructor
        + +switchInputMethod +
        + + +
        T  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +U +V +W +Y + TOP +

        +TERTIARY_EMAIL +
        + +TERTIARY_EMAIL_TYPE +
        + +TERTIARY_PHONE +
        + +TERTIARY_PHONE_TYPE +
        + +TestMethod
        +  TestMethod +(String, Class<TestCase>) constructor
        + +  TestMethod +(TestCase) constructor
        + +TextAppearanceSpan +(Parcel) constructor
        + +TextView.OnEditorActionListener
        + +Theme_InputMethod +
        + +Theme_Light_Panel +
        + +Theme_NoDisplay +
        + +Theme_Panel +
        + +thickness +
        + +title_bar_tall +
        + +topOffset +
        + +toShortString
        +  type  +() in android.graphics.Rect +
        + +  type  +() in android.view.animation.Transformation +
        + +TransitionDrawable +(Drawable[]) constructor
        + +TYPE_APPLICATION_ATTACHED_DIALOG +
        + +TYPE_INPUT_METHOD +
        + +TYPE_INPUT_METHOD_DIALOG +
        + +TypefaceSpan +(Parcel) constructor
        + + +
        U  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +V +W +Y + TOP +

        +UnderlineSpan +(Parcel) constructor
        + +UNKNOWN_LENGTH +
        + +unregisterListener
        +  type  +(SensorEventListener) in android.hardware.SensorManager +
        + +  type  +(SensorEventListener, Sensor) in android.hardware.SensorManager +
        + +update
        +  type  +() in android.widget.PopupWindow +
        + +  type  +(int, int, int, int, boolean) in android.widget.PopupWindow +
        + +UPDATE_DEVICE_STATS +
        + +UpdateAppearance
        + +updatePeriodMillis +
        + +URLSpan +(Parcel) constructor
        + +UserDictionary
        + +UserDictionary.Words
        + + +
        V  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +W +Y + TOP +

        +verticalCorrection +
        + +verticalGap +
        + +VideoView_error_text_invalid_progressive_playback +
        + +ViewDebug.CapturedViewProperty
        + +ViewTreeObserver.OnScrollChangedListener
        + +Visibility
        + +voiceLanguage +
        + +voiceLanguageModel +
        + +voiceMaxResults +
        + +voicePromptText +
        + +voiceSearchMode +
        + +VOLUME_NOTIFICATION +
        + + +
        W  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +Y + TOP +

        +Widget_KeyboardView +
        + +WIFI_MAX_DHCP_RETRY_COUNT +
        + +WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS +
        + +WIFI_MODE_FULL +
        + +WIFI_MODE_SCAN_ONLY +
        + +WIFI_SLEEP_POLICY +
        + +WIFI_SLEEP_POLICY_DEFAULT +
        + +WIFI_SLEEP_POLICY_NEVER +
        + +WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED +
        + +windowDisablePreview +
        + +windowNoDisplay +
        + +windowSoftInputMode +
        + +WRITE_SECURE_SETTINGS +
        + +writeToParcel
        +  type  +(Parcel, int) in android.content.res.AssetFileDescriptor +
        + +  type  +(Parcel, int) in android.graphics.RectF +
        + +  type  +(Parcel, int) in android.text.Annotation +
        + +  type  +(Parcel, int) in android.text.style.AbsoluteSizeSpan +
        + +  type  +(Parcel, int) in android.text.style.AlignmentSpan.Standard +
        + +  type  +(Parcel, int) in android.text.style.BackgroundColorSpan +
        + +  type  +(Parcel, int) in android.text.style.BulletSpan +
        + +  type  +(Parcel, int) in android.text.style.ForegroundColorSpan +
        + +  type  +(Parcel, int) in android.text.style.LeadingMarginSpan.Standard +
        + +  type  +(Parcel, int) in android.text.style.QuoteSpan +
        + +  type  +(Parcel, int) in android.text.style.RelativeSizeSpan +
        + +  type  +(Parcel, int) in android.text.style.ScaleXSpan +
        + +  type  +(Parcel, int) in android.text.style.StrikethroughSpan +
        + +  type  +(Parcel, int) in android.text.style.StyleSpan +
        + +  type  +(Parcel, int) in android.text.style.SubscriptSpan +
        + +  type  +(Parcel, int) in android.text.style.SuperscriptSpan +
        + +  type  +(Parcel, int) in android.text.style.TextAppearanceSpan +
        + +  type  +(Parcel, int) in android.text.style.TypefaceSpan +
        + +  type  +(Parcel, int) in android.text.style.URLSpan +
        + +  type  +(Parcel, int) in android.text.style.UnderlineSpan +
        + + +
        Y  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W + TOP +

        +yieldIfContendedSafely +()
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/alldiffs_index_all.html b/docs/html/sdk/api_diff/3/changes/alldiffs_index_all.html new file mode 100644 index 0000000000000000000000000000000000000000..48da98bb87766ad4f5d05bfefcee385b699472f4 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/alldiffs_index_all.html @@ -0,0 +1,4178 @@ + + + + + + + + + +All Differences Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Differences +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + + +
        A  +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +AbsListView
        + +AbsoluteLayout
        + +AbsoluteSizeSpan
        +  android.text.style
        + +  AbsoluteSizeSpan +(Parcel) constructor
        + +AbsSeekBar
        + +ACCELEROMETER_ROTATION +
        + +ACTION_AIRPLANE_MODE_SETTINGS +
        + +ACTION_APPLICATION_DEVELOPMENT_SETTINGS +
        + +ACTION_AUDIO_BECOMING_NOISY +
        + +ACTION_BACKGROUND_DATA_SETTING_CHANGED +
        + +ACTION_DATA_ROAMING_SETTINGS +
        + +ACTION_IMAGE_CAPTURE +
        + +ACTION_INPUT_METHOD_CHANGED +
        + +ACTION_INPUT_METHOD_SETTINGS +
        + +ACTION_INTERNAL_STORAGE_SETTINGS +
        + +ACTION_MANAGE_APPLICATIONS_SETTINGS +
        + +ACTION_MEDIA_CHECKING +
        + +ACTION_MEDIA_NOFS +
        + +ACTION_MEMORY_CARD_SETTINGS +
        + +ACTION_NETWORK_OPERATOR_SETTINGS +
        + +ACTION_OUTSIDE +
        + +ACTION_PACKAGE_DATA_CLEARED +
        + +ACTION_PACKAGE_REPLACED +
        + +ACTION_PHONE_STATE_CHANGED +
        + +ACTION_QUICK_LAUNCH_SETTINGS +
        + +ACTION_SEARCH_LONG_PRESS +
        + +ACTION_SYNC_SETTINGS +
        + +ACTION_SYSTEM_TUTORIAL +
        + +ACTION_USER_DICTIONARY_SETTINGS +
        + +ACTION_USER_PRESENT +
        + +ACTION_VIDEO_CAPTURE +
        + +ACTION_WIFI_IP_SETTINGS +
        + +Activity
        + +ActivityInfo
        + +ActivityInstrumentationTestCase
        + +ActivityInstrumentationTestCase2
        + +ActivityManager
        + +ActivityManager.RunningAppProcessInfo
        + +ADB_ENABLED +
        + +addGpsStatusListener +(Listener)
        + +addOnScrollChangedListener +(OnScrollChangedListener)
        + +addPropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        + +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        + +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        + +addRequirements +(Predicate<TestMethod>)
        + +addTestProvider +(String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int)
        + +addToDictionary +
        + +adjustMetaAfterKeypress +(long)
        + +AlarmManager
        + +AlertDialog
        + +ALIGN_BASELINE +
        + +ALIGN_BOTTOM +
        + +AlignmentSpan.Standard
        +  android.text.style
        + +  AlignmentSpan.Standard +(Parcel) constructor
        + +allowSingleTap +
        + +AlphabetIndexer
        + +android
        + +android.app
        + +android.appwidget
        + +android.content
        + +android.content.pm
        + +android.content.res
        + +android.database
        + +android.database.sqlite
        + +android.graphics
        + +android.graphics.drawable
        + +android.graphics.drawable.shapes
        + +android.hardware
        + +android.inputmethodservice
        + +android.location
        + +android.media
        + +android.net
        + +android.net.wifi
        + +android.opengl
        + +android.os
        + +android.preference
        + +android.provider
        + +android.speech
        + +android.telephony
        + +android.telephony.gsm
        + +android.test
        + +android.test.mock
        + +android.test.suitebuilder
        + +android.text
        + +android.text.format
        + +android.text.method
        + +android.text.style
        + +android.util
        + +android.view
        + +android.view.animation
        + +android.view.inputmethod
        + +android.webkit
        + +android.widget
        + +ANDROID_ID +
        + +animateOnClick +
        + +Animation
        + +Annotation
        +  android.text
        + +  Annotation +(Parcel) constructor
        + +appendEscapedSQLString +(StringBuilder, String)
        + +applyDisplay +(int, Rect, Rect)
        + +ArrayAdapter
        + +ArrowKeyMovementMethod
        + +AssetFileDescriptor
        + +AssetFileDescriptor.AutoCloseInputStream
        + +AssetFileDescriptor.AutoCloseOutputStream
        + +AsyncTask
        + +AsyncTask.Status
        + +AudioFormat
        + +AudioManager
        + +AudioRecord
        + +AudioRecord.OnRecordPositionUpdateListener
        + +AudioTrack
        + +AudioTrack.OnPlaybackPositionUpdateListener
        + +AutoCompleteTextView
        + +AutoText
        + +autoText +
        + +AXIS_CLIP +
        + +AXIS_MINUS_X +
        + +AXIS_MINUS_Y +
        + +AXIS_MINUS_Z +
        + +AXIS_X +
        + +AXIS_Y +
        + +AXIS_Z +
        + + +
        B  +A +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +BackgroundColorSpan
        +  android.text.style
        + +  BackgroundColorSpan +(Parcel) constructor
        + +backgroundDimEnabled +
        + +BaseKeyListener
        + +beginBatchEdit +()
        + +BIND_APPWIDGET +
        + +BIND_INPUT_METHOD +
        + +Binder
        + +Bitmap
        + +BLUETOOTH_ON +
        + +BOOKMARK +
        + +bottomOffset +
        + +bringPointIntoView +(int)
        + +BroadcastReceiver
        + +Browser
        + +BUCKET_DISPLAY_NAME +
        + +BUCKET_ID +
        + +Build
        + +BulletSpan
        +  android.text.style
        + +  BulletSpan +(Parcel) constructor
        + +BUTTON1 +
        + +BUTTON2 +
        + +BUTTON3 +
        + +BUTTON_NEGATIVE +
        + +BUTTON_NEUTRAL +
        + +BUTTON_POSITIVE +
        + + +
        C  +A +B +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +calculateLength +(CharSequence, boolean)
        + +callActivityOnUserLeaving +(Activity)
        + +Camera
        + +candidatesArea +
        + +candidatesTextStyleSpans +
        + +Canvas
        + +CAP_MODE_CHARACTERS +
        + +CAP_MODE_SENTENCES +
        + +CAP_MODE_WORDS +
        + +capitalize +
        + +CATEGORY_GADGET +
        + +CATEGORY_INFO +
        + +changeAction +(KeyEvent, int)
        + +changeCursorAndColumns +(Cursor, String[], int[])
        + +changeDebugPort +(int)
        + +changeFlags +(KeyEvent, int)
        + +changeTimeRepeat +(KeyEvent, long, int)
        + +Character.UnicodeBlock
        + +checkInputConnectionProxy +(View)
        + +Chronometer
        + +Chronometer.OnChronometerTickListener
        + +Class
        + +clearComposingText +()
        + +clearListSelection +()
        + +clearMatches +()
        + +clearMetaKeyState
        +  type  +(View, Editable, int) in android.text.method.KeyListener +
        + +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        + +  type  +(View, Editable, int) in android.text.method.MetaKeyKeyListener +
        + +  type  +(Editable, int) in android.text.method.MetaKeyKeyListener +
        + +clearTestProviderEnabled +(String)
        + +clearTestProviderLocation +(String)
        + +clearTestProviderStatus +(String)
        + +ClickableSpan
        + +CLIP_HORIZONTAL +
        + +CLIP_VERTICAL +
        + +clone +()
        + +close +()
        + +closeButton +
        + +closeContextMenu +()
        + +codes +
        + +computeDurationHint +()
        + +configPreferences +
        + +Configuration
        + +ConfigurationInfo
        + +configure +
        + +ConnectivityManager
        + +Contacts.Intents
        + +Contacts.Intents.Insert
        + +Contacts.PeopleColumns
        + +content +
        + +ContentProvider
        + +ContentResolver
        + +Context
        + +copy +
        + +copyPixelsFromBuffer +(Buffer)
        + +copyUrl +
        + +createInputStream +()
        + +createOutputStream +()
        + +createWifiLock +(int, String)
        + +CREATOR
        + in  +android.content.res.AssetFileDescriptor +
        + + in  +android.graphics.RectF +
        + +Cursor
        + +CursorAdapter
        + +CursorWrapper
        + +cut +
        + + +dalvik.system
        + +dark_header +
        + +DATA_ROAMING +
        + +DATA_X +
        + +DATA_Y +
        + +DATA_Z +
        + +DatabaseUtils
        + +Date
        +  java.util
        + +  Date +() constructor
        + +  Date +(int, int, int, int, int, int) constructor
        + +DateKeyListener
        + +DateTimeKeyListener
        + +Debug
        + +DEBUG_ENABLE_ASSERT +
        + +DEBUG_ENABLE_CHECKJNI +
        + +DEBUG_ENABLE_DEBUGGER +
        + +DEFAULT_SORT_ORDER
        + in  +android.provider.MediaStore.Images.Media +
        + + in  +android.provider.MediaStore.Video +
        + +describeContents
        +  type  +() in android.content.res.AssetFileDescriptor +
        + +  type  +() in android.graphics.RectF +
        + +  type  +() in android.text.Annotation +
        + +  type  +() in android.text.style.AbsoluteSizeSpan +
        + +  type  +() in android.text.style.AlignmentSpan.Standard +
        + +  type  +() in android.text.style.BackgroundColorSpan +
        + +  type  +() in android.text.style.BulletSpan +
        + +  type  +() in android.text.style.ForegroundColorSpan +
        + +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        + +  type  +() in android.text.style.QuoteSpan +
        + +  type  +() in android.text.style.RelativeSizeSpan +
        + +  type  +() in android.text.style.ScaleXSpan +
        + +  type  +() in android.text.style.StrikethroughSpan +
        + +  type  +() in android.text.style.StyleSpan +
        + +  type  +() in android.text.style.SubscriptSpan +
        + +  type  +() in android.text.style.SuperscriptSpan +
        + +  type  +() in android.text.style.TextAppearanceSpan +
        + +  type  +() in android.text.style.TypefaceSpan +
        + +  type  +() in android.text.style.URLSpan +
        + +  type  +() in android.text.style.UnderlineSpan +
        + +DEVICE_PROVISIONED +
        + +deviceHasKey +(int)
        + +deviceHasKeys +(int[])
        + +DexClassLoader
        + +DexFile
        + +DialerKeyListener
        + +dialog_alert_title +
        + +DialogInterface
        + +DialogPreference
        + +didTouchFocusSelect +()
        + +DigitsKeyListener
        + +dispatchKeyEventPreIme +(KeyEvent)
        + +DISPLAY +
        + +DISPLAY_CLIP_HORIZONTAL +
        + +DISPLAY_CLIP_VERTICAL +
        + +drag
        +  type  +(InstrumentationTestCase, float, float, float, float, int) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, float, float, float, float, int) in android.test.TouchUtils +
        + +dragQuarterScreenDown
        +  type  +(InstrumentationTestCase, Activity) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase) in android.test.TouchUtils +
        + +dragQuarterScreenUp
        +  type  +(InstrumentationTestCase, Activity) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase) in android.test.TouchUtils +
        + +dragViewBy
        +  type  +(InstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        + +dragViewTo
        +  type  +(InstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        + +dragViewToBottom
        +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        + +  type  +(InstrumentationTestCase, Activity, View, int) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        + +  type  +(InstrumentationTestCase, Activity, View) in android.test.TouchUtils +
        + +dragViewToTop
        +  type  +(InstrumentationTestCase, View) in android.test.TouchUtils +
        + +  type  +(InstrumentationTestCase, View, int) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        + +dragViewToX
        +  type  +(InstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        + +dragViewToY
        +  type  +(InstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        + +Drawable
        + +drawBitmap +(int[], int, int, float, float, int, int, boolean, Paint)
        + +dropDownAnchor +
        + +dropDownWidth +
        + +dump
        +  type  +(Printer, String) in android.location.Location +
        + +  type  +(FileDescriptor, String[]) in android.os.Binder +
        + +  type  +(FileDescriptor, String[]) in android.os.IBinder +
        + +dumpCapturedView +(String, Object)
        + +dumpHprofData
        +  type  +(String) in android.os.Debug +
        + +  type  +(String) in dalvik.system.VMDebug +
        + +dumpSpans +(CharSequence, Printer, String)
        + +DynamicDrawableSpan
        +  android.text.style
        + +  DynamicDrawableSpan +(int) constructor
        + + +
        E  +A +B +C +D +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +editable +
        + +editorExtras +
        + +enabled +
        + +endBatchEdit +()
        + +Environment
        + +EXTRA_APPLICATION_ID +
        + +EXTRA_CREATE_DESCRIPTION +
        + +EXTRA_DATA_REMOVED +
        + +EXTRA_FINISH_ON_COMPLETION +
        + +EXTRA_FORCE_CREATE +
        + +EXTRA_INCOMING_NUMBER +
        + +EXTRA_MAX_BYTES +
        + +EXTRA_MEDIA_ALBUM +
        + +EXTRA_MEDIA_ARTIST +
        + +EXTRA_MEDIA_FOCUS +
        + +EXTRA_MEDIA_TITLE +
        + +EXTRA_OUTPUT +
        + +EXTRA_REPLACING +
        + +EXTRA_SCREEN_ORIENTATION +
        + +EXTRA_STATE +
        + +EXTRA_STATE_IDLE +
        + +EXTRA_STATE_OFFHOOK +
        + +EXTRA_STATE_RINGING +
        + +EXTRA_VIDEO_QUALITY +
        + +extractArea +
        + +extractText +(ExtractedTextRequest, ExtractedText)
        + + +
        F  +A +B +C +D +E +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +fastScrollEnabled +
        + +fillEnabled +
        + +findAll +(String)
        + +findNext +(boolean)
        + +FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET +
        + +FLAG_ACTIVITY_NO_USER_ACTION +
        + +FLAG_ACTIVITY_REORDER_TO_FRONT +
        + +FLAG_ALT_FOCUSABLE_IM +
        + +FLAG_EDITOR_ACTION +
        + +FLAG_FROM_SYSTEM +
        + +FLAG_KEEP_TOUCH_MODE +
        + +FLAG_NO_HISTORY +
        + +FLAG_SOFT_KEYBOARD +
        + +FLAG_UPDATE_CURRENT +
        + +FLAG_WATCH_OUTSIDE_TOUCH +
        + +footerDividersEnabled +
        + +ForegroundColorSpan
        +  android.text.style
        + +  ForegroundColorSpan +(Parcel) constructor
        + +forkAndSpecialize
        +  type  +(int, int, int[], int, int[][]) in dalvik.system.Zygote +
        + +  type  +(int, int, int[], boolean, int[][]) in dalvik.system.Zygote +
        + +forkSystemServer
        +  type  +(int, int, int[], int, int[][]) in dalvik.system.Zygote +
        + +  type  +(int, int, int[], boolean, int[][]) in dalvik.system.Zygote +
        + +FORMAT_JAPAN +
        + +formatJapaneseNumber +(Editable)
        + +forName +(String)
        + +FX_KEYPRESS_DELETE +
        + +FX_KEYPRESS_RETURN +
        + +FX_KEYPRESS_SPACEBAR +
        + +FX_KEYPRESS_STANDARD +
        + + +
        G  +A +B +C +D +E +F +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +GeomagneticField
        + +GestureDetector
        +  android.view
        + +  GestureDetector +(Context, OnGestureListener) constructor
        + +  GestureDetector +(Context, OnGestureListener, Handler) constructor
        + +  GestureDetector +(OnGestureListener) constructor
        + +  GestureDetector +(OnGestureListener, Handler) constructor
        + +GestureDetector.OnDoubleTapListener
        + +GestureDetector.SimpleOnGestureListener
        + +get +(Context)
        + +GET_CONFIGURATIONS +
        + +GET_UNINSTALLED_PACKAGES +
        + +getAllowFileAccess +()
        + +getBackgroundDataSetting +()
        + +getBoolean +(int)
        + +getBuiltInZoomControls +()
        + +getButton +(int)
        + +getCapsMode +(CharSequence, int, int)
        + +getCharacters +()
        + +getClasses +()
        + +getColumnIndex
        +  type  +(String) in android.database.Cursor +
        + +  type  +(String) in android.database.CursorWrapper +
        + +getConstructors +()
        + +getCount +()
        + +getDeclaredClasses +()
        + +getDeclaredConstructors +()
        + +getDeclaredLength +()
        + +getDefaultSensor +(int)
        + +getDeviceConfigurationInfo +()
        + +getDialog +()
        + +getDoubleTapTimeout +()
        + +getDrawable
        +  type  +() in android.graphics.drawable.RotateDrawable +
        + +  type  +() in android.graphics.drawable.ScaleDrawable +
        + +getDropDownAnchor +()
        + +getDropDownWidth +()
        + +getEdgeSlop +()
        + +getEditableText +()
        + +getFadingEdgeLength +()
        + +getFraction +(int, int, int)
        + +getGpsStatus +(GpsStatus)
        + +getHandler +()
        + +getImeActionId +()
        + +getImeActionLabel +()
        + +getImeOptions +()
        + +getInclination +(float[])
        + +getInitialScrollX +(TextView, Spannable)
        + +getInitialScrollY +(TextView, Spannable)
        + +getInputExtras +(boolean)
        + +getInputMethodMode +()
        + +getInputType
        +  type  +() in android.text.method.DateKeyListener +
        + +  type  +() in android.text.method.DateTimeKeyListener +
        + +  type  +() in android.text.method.DialerKeyListener +
        + +  type  +() in android.text.method.DigitsKeyListener +
        + +  type  +() in android.text.method.KeyListener +
        + +  type  +() in android.text.method.MultiTapKeyListener +
        + +  type  +() in android.text.method.QwertyKeyListener +
        + +  type  +() in android.text.method.TextKeyListener +
        + +  type  +() in android.text.method.TimeKeyListener +
        + +  type  +() in android.widget.TextView +
        + +getInterfaces +()
        + +getItem
        +  type  +(int) in android.view.Menu +
        + +  type  +(int) in android.widget.CursorAdapter +
        + +getItemClickListener +()
        + +getItemId +(int)
        + +getItemSelectedListener +()
        + +getKeyProgressIncrement +()
        + +getLaunchIntentForPackage
        +  type  +(String) in android.content.pm.PackageManager +
        + +  type  +(String) in android.test.mock.MockPackageManager +
        + +getLayoutDimension +(int, int)
        + +getListSelection +()
        + +getListView +()
        + +getLoggingMXBean +()
        + +getLong
        +  type  +(ContentResolver, String) in android.provider.Settings.System +
        + +  type  +(ContentResolver, String, long) in android.provider.Settings.System +
        + +getMaxAvailableHeight +(View, int)
        + +getMaximumDrawingCacheSize +()
        + +getMaxKeyCode +()
        + +getMetaState
        +  type  +(long) in android.text.method.MetaKeyKeyListener +
        + +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        + +getMinimumFlingVelocity +()
        + +getNeighboringCellInfo +()
        + +getOnChronometerTickListener +()
        + +getOnItemClickListener +()
        + +getOnItemSelectedListener +()
        + +getOrientation +(float[], float[])
        + +getOriginalUrl
        +  type  +() in android.webkit.WebHistoryItem +
        + +  type  +() in android.webkit.WebView +
        + +getPluginData
        +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptHandler +
        + +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptRegistry +
        + +getPrivateImeOptions +()
        + +getProxyClass +(ClassLoader, Class<?>)
        + +getRotationMatrix +(float[], float[], float[], float[])
        + +getRunningAppProcesses +()
        + +getScaledDoubleTapSlop +()
        + +getScaledEdgeSlop +()
        + +getScaledFadingEdgeLength +()
        + +getScaledMaximumDrawingCacheSize +()
        + +getScaledMinimumFlingVelocity +()
        + +getScaledScrollBarSize +()
        + +getScaledTouchSlop +()
        + +getScaledWindowTouchSlop +()
        + +getScrollBarSize +()
        + +getSensorList +(int)
        + +getSensors +()
        + +getSize +(View)
        + +getSpanTypeId
        +  type  +() in android.text.Annotation +
        + +  type  +() in android.text.style.AbsoluteSizeSpan +
        + +  type  +() in android.text.style.AlignmentSpan.Standard +
        + +  type  +() in android.text.style.BackgroundColorSpan +
        + +  type  +() in android.text.style.BulletSpan +
        + +  type  +() in android.text.style.ForegroundColorSpan +
        + +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        + +  type  +() in android.text.style.QuoteSpan +
        + +  type  +() in android.text.style.RelativeSizeSpan +
        + +  type  +() in android.text.style.ScaleXSpan +
        + +  type  +() in android.text.style.StrikethroughSpan +
        + +  type  +() in android.text.style.StyleSpan +
        + +  type  +() in android.text.style.SubscriptSpan +
        + +  type  +() in android.text.style.SuperscriptSpan +
        + +  type  +() in android.text.style.TextAppearanceSpan +
        + +  type  +() in android.text.style.TypefaceSpan +
        + +  type  +() in android.text.style.URLSpan +
        + +  type  +() in android.text.style.UnderlineSpan +
        + +getStartX +()
        + +getStartY +()
        + +getStatSize +()
        + +getSubtype +()
        + +getSubtypeName +()
        + +getSurrogate +(String, Map<String, String>)
        + +getSystemSharedLibraryNames
        +  type  +() in android.content.pm.PackageManager +
        + +  type  +() in android.test.mock.MockPackageManager +
        + +getTargetIntent +()
        + +getTextFilter +()
        + +getThread +()
        + +getTimeZoneDatabaseVersion +()
        + +getTouchSlop +()
        + +getUserAgent +()
        + +getUserAgentString +()
        + +getVerticalAlignment +()
        + +getWindowTouchSlop +()
        + +getWindowVisibleDisplayFrame +(Rect)
        + +getZoomControls +()
        + +GLSurfaceView
        + +GLSurfaceView.EGLConfigChooser
        + +GLSurfaceView.GLWrapper
        + +GLSurfaceView.Renderer
        + +GpsSatellite
        + +GpsStatus
        + +GpsStatus.Listener
        + +Gravity
        + +GridView
        + + +
        H  +A +B +C +D +E +F +G +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +handle +
        + +handleKeyDown +(long, int, KeyEvent)
        + +handleKeyUp +(long, int, KeyEvent)
        + +Handler
        +  android.os
        + +  Handler +(Callback) constructor
        + +  Handler +(Looper, Callback) constructor
        + +Handler.Callback
        + +HAPTIC_FEEDBACK_ENABLED
        + in  +android.provider.Settings.System +
        + + in  +android.view.View +
        + +HapticFeedbackConstants
        + +hapticFeedbackEnabled +
        + +hardKeyboardHidden +
        + +HARDKEYBOARDHIDDEN_NO +
        + +HARDKEYBOARDHIDDEN_UNDEFINED +
        + +HARDKEYBOARDHIDDEN_YES +
        + +hasSoftInputMode +()
        + +hasWindowFocus +()
        + +headerDividersEnabled +
        + +horizontalGap +
        + +HorizontalScrollView
        + +HTTP_PROXY +
        + + +
        I  +A +B +C +D +E +F +G +H +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +IBinder
        + +ic_btn_speak_now +
        + +iconPreview +
        + +ImageSpan
        +  android.text.style
        + +  ImageSpan +(Context, Uri, int) constructor
        + +  ImageSpan +(Context, int, int) constructor
        + +  ImageSpan +(Bitmap, int) constructor
        + +  ImageSpan +(Drawable, int) constructor
        + +  ImageSpan +(Drawable, String, int) constructor
        + +imeActionId +
        + +imeActionLabel +
        + +imeExtractEnterAnimation +
        + +imeExtractExitAnimation +
        + +imeFullscreenBackground +
        + +imeOptions +
        + +inferStreamType +()
        + +initialLayout +
        + +innerRadius +
        + +INPUT_METHOD_FROM_FOCUSABLE +
        + +INPUT_METHOD_NEEDED +
        + +INPUT_METHOD_NOT_NEEDED +
        + +INPUT_METHOD_SERVICE +
        + +inputArea +
        + +inputExtractEditText +
        + +inputMethod +
        + +InputType
        + +inputType +
        + +INSTALL_FAILED_CONFLICTING_PROVIDER +
        + +INSTALL_NON_MARKET_APPS +
        + +Instrumentation
        + +InstrumentationTestCase
        + +Intent
        + +INTENT_ACTION_MEDIA_SEARCH +
        + +INTENT_ACTION_STILL_IMAGE_CAMERA +
        + +INTENT_ACTION_VIDEO_CAMERA +
        + +intentForPosition +(int)
        + +IntentService
        + +INTERVAL_DAY +
        + +INTERVAL_FIFTEEN_MINUTES +
        + +INTERVAL_HALF_DAY +
        + +INTERVAL_HALF_HOUR +
        + +INTERVAL_HOUR +
        + +isAboveAnchor +()
        + +isBluetoothA2dpOn +()
        + +isClippingEnabled +()
        + +isCookielessProxyUrl +(String)
        + +isDebuggingEnabled +()
        + +isDefault +
        + +isFastScrollEnabled +()
        + +isFillEnabled +()
        + +isHapticFeedbackEnabled +()
        + +isInEditMode +()
        + +isInputMethodTarget +()
        + +isLooping +()
        + +isModifier +
        + +isOutsideTouchable +()
        + +isPerformingCompletion +()
        + +isRepeatable +
        + +isRoaming +()
        + +isSafeMode
        +  type  +() in android.content.pm.PackageManager +
        + +  type  +() in android.test.mock.MockPackageManager +
        + +isScrollContainer +
        + +isSelectingMetaTracker +(CharSequence, Object)
        + +isSmoothScrollbarEnabled +()
        + +isSticky +
        + +isTouchable +()
        + + +java.beans
        + +java.lang
        + +java.lang.reflect
        + +java.net
        + +java.util
        + +java.util.jar
        + +java.util.logging
        + +JetPlayer
        + +JetPlayer.OnJetEventListener
        + + +
        K  +A +B +C +D +E +F +G +H +I +J +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +KEY_LOCATION_CHANGED +
        + +KEY_PROVIDER_ENABLED +
        + +KEY_STATUS_CHANGED +
        + +keyBackground +
        + +keyboardMode +
        + +keyboardView +
        + +KeyCharacterMap
        + +KEYCODE_MEDIA_FAST_FORWARD +
        + +KEYCODE_MEDIA_NEXT +
        + +KEYCODE_MEDIA_PLAY_PAUSE +
        + +KEYCODE_MEDIA_PREVIOUS +
        + +KEYCODE_MEDIA_REWIND +
        + +KEYCODE_MEDIA_STOP +
        + +KEYCODE_MUTE +
        + +keyEdgeFlags +
        + +KeyEvent
        +  android.view
        + +  KeyEvent +(KeyEvent) constructor
        + +  KeyEvent +(long, String, int, int) constructor
        + +keyHeight +
        + +keyIcon +
        + +keyLabel +
        + +KeyListener
        + +keyOutputText +
        + +keyPreviewHeight +
        + +keyPreviewLayout +
        + +keyPreviewOffset +
        + +keyTextColor +
        + +keyTextSize +
        + +keyWidth +
        + + +
        L  +A +B +C +D +E +F +G +H +I +J +K +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +labelTextSize +
        + +launchActivityWithIntent +(String, Class<T>, Intent)
        + +LauncherActivity
        + +LauncherActivity.IconResizer
        + +LauncherActivity.ListItem
        + +LeadingMarginSpan.Standard
        +  android.text.style
        + +  LeadingMarginSpan.Standard +(Parcel) constructor
        + +Level
        + +LIGHT_NO_MOON +
        + +ListView
        + +LiveFolders
        + +load
        +  type  +(AssetFileDescriptor, int) in android.media.SoundPool +
        + +  type  +(FileDescriptor, long, long, int) in android.media.SoundPool +
        + +loadDex +(String, String, int)
        + +Location
        + +LOCATION_PROVIDERS_ALLOWED +
        + +LocationManager
        + +LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED +
        + +LOGGING_ID +
        + +LogManager
        + +longClickView
        +  type  +(InstrumentationTestCase, View) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        + +Looper
        + + +
        M  +A +B +C +D +E +F +G +H +I +J +K +L +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +makeListItems +()
        + +Manifest.permission
        + +MaskFilterSpan
        + +MAX_KEYCODE +
        + +mayUseInputMethod +(int)
        + +MEDIA_CHECKING +
        + +MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK +
        + +MEDIA_INFO_BAD_INTERLEAVING +
        + +MEDIA_INFO_NOT_SEEKABLE +
        + +MEDIA_INFO_UNKNOWN +
        + +MEDIA_INFO_VIDEO_TRACK_LAGGING +
        + +MEDIA_NOFS +
        + +MEDIA_RECORDER_ERROR_UNKNOWN +
        + +MEDIA_RECORDER_INFO_MAX_DURATION_REACHED +
        + +MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED +
        + +MEDIA_RECORDER_INFO_UNKNOWN +
        + +MediaPlayer
        + +MediaPlayer.OnInfoListener
        + +MediaPlayer.OnVideoSizeChangedListener
        + +MediaRecorder
        + +MediaRecorder.OnErrorListener
        + +MediaRecorder.OnInfoListener
        + +MediaRecorder.OutputFormat
        + +MediaRecorder.VideoEncoder
        + +MediaRecorder.VideoSource
        + +MediaStore
        + +MediaStore.Audio.AlbumColumns
        + +MediaStore.Audio.Media
        + +MediaStore.Images.Media
        + +MediaStore.Video
        + +MediaStore.Video.VideoColumns
        + +Menu
        + +MetaKeyKeyListener
        + +MockPackageManager
        + +MODE_APPEND +
        + +MotionEvent
        + +MOUNT_FORMAT_FILESYSTEMS +
        + +moveCursorToVisibleOffset +()
        + +MovementMethod
        + +MultiTapKeyListener
        + +mutate +()
        + +mVerticalAlignment +
        + + +
        N  +A +B +C +D +E +F +G +H +I +J +K +L +M +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +NeighboringCellInfo
        + +NETWORK_PREFERENCE +
        + +NetworkInfo
        +  android.net
        + +  NetworkInfo +(int) constructor
        + +NoCopySpan
        + +NoCopySpan.Concrete
        + +noHistory +
        + +NUM_STREAMS +
        + +NUMBER_OF_SONGS_FOR_ARTIST +
        + +numeric +
        + + +
        O  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +onBeginBatchEdit +()
        + +onCheckIsTextEditor +()
        + +onCommitCompletion +(CompletionInfo)
        + +onContentChanged +()
        + +onCreateInputConnection +(EditorInfo)
        + +onDoubleTap +(MotionEvent)
        + +onDoubleTapEvent +(MotionEvent)
        + +onEditorAction +(int)
        + +onEndBatchEdit +()
        + +onFinishTemporaryDetach +()
        + +onGlobalFocusChanged +(View, View)
        + +onKeyOther
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ArrowKeyMovementMethod +
        + +  type  +(View, Editable, KeyEvent) in android.text.method.BaseKeyListener +
        + +  type  +(View, Editable, KeyEvent) in android.text.method.KeyListener +
        + +  type  +(TextView, Spannable, KeyEvent) in android.text.method.MovementMethod +
        + +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ScrollingMovementMethod +
        + +onKeyPreIme +(int, KeyEvent)
        + +onPrivateIMECommand +(String, Bundle)
        + +onRestoreInstanceState +(Parcelable)
        + +onSaveInstanceState +()
        + +onSelectionChanged +(int, int)
        + +onSingleTapConfirmed +(MotionEvent)
        + +onStartTemporaryDetach +()
        + +onTextContextMenuItem +(int)
        + +onUserInteraction +()
        + +onUserLeaveHint +()
        + +openAssetFile +(Uri, String)
        + +openAssetFileDescriptor +(Uri, String)
        + +openOutputStream +(Uri, String)
        + +openRawResource +(int, TypedValue)
        + +OrientationEventListener
        + +OrientationListener
        +  android.view
        + +  OrientationListener +(Context, int) constructor
        + + +
        P  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +Q +R +S +T +U +V +W +Y +Z + TOP +

        +Pack200.Packer
        + +Pack200.Unpacker
        + +PackageInfo
        + +PackageManager
        + +Parcel
        + +ParcelableSpan
        + +ParcelFileDescriptor
        + +PARENTAL_CONTROL_ENABLED +
        + +PARENTAL_CONTROL_LAST_UPDATE +
        + +PARENTAL_CONTROL_REDIRECT_URL +
        + +parse +(String)
        + +parseBundleExtra +(String, AttributeSet, Bundle)
        + +parseBundleExtras +(XmlResourceParser, Bundle)
        + +password +
        + +paste +
        + +peekService +(Context, Intent)
        + +PendingIntent
        + +performHapticFeedback
        +  type  +(int) in android.view.View +
        + +  type  +(int, int) in android.view.View +
        + +phoneNumber +
        + +PhoneNumberUtils
        + +PHONETIC_NAME
        + in  +android.provider.Contacts.Intents.Insert +
        + + in  +android.provider.Contacts.PeopleColumns +
        + +playSoundEffect
        +  type  +(int, float) in android.media.AudioManager +
        + +  type  +(int) in android.view.View +
        + +PluginData
        + +popupCharacters +
        + +popupKeyboard +
        + +popupLayout +
        + +PopupWindow
        + +PopupWindow.OnDismissListener
        + +prepare +()
        + +PrintStreamPrinter
        + +privateImeOptions +
        + +ProgressBar
        + +ProviderTestCase
        + +ProviderTestCase2
        + +Proxy
        + +putLong +(ContentResolver, String, long)
        + + +
        Q  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +R +S +T +U +V +W +Y +Z + TOP +

        +QuoteSpan
        +  android.text.style
        + +  QuoteSpan +(Parcel) constructor
        + +QwertyKeyListener
        + + +
        R  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +S +T +U +V +W +Y +Z + TOP +

        +R.attr
        + +R.bool
        + +R.drawable
        + +R.id
        + +R.integer
        + +R.string
        + +R.style
        + +RasterizerSpan
        + +RAW_AMR +
        + +RAW_DATA_INDEX +
        + +RAW_DATA_X +
        + +RAW_DATA_Y +
        + +RAW_DATA_Z +
        + +readFromParcel +(Parcel)
        + +readHashMap +(ClassLoader)
        + +readMap +(Map, ClassLoader)
        + +Rect
        + +RectF
        + +registerListener
        +  type  +(SensorEventListener, Sensor, int) in android.hardware.SensorManager +
        + +  type  +(SensorEventListener, Sensor, int, Handler) in android.hardware.SensorManager +
        + +  type  +(SensorListener, int) in android.hardware.SensorManager +
        + +  type  +(SensorListener, int, int) in android.hardware.SensorManager +
        + +RelativeSizeSpan
        +  android.text.style
        + +  RelativeSizeSpan +(Parcel) constructor
        + +remapCoordinateSystem +(float[], int, int, float[])
        + +RemoteViews
        + +RemoteViews.ActionException
        +  android.widget
        + +  RemoteViews.ActionException +(Exception) constructor
        + +removeAt +(int)
        + +removeGpsStatusListener +(Listener)
        + +removeOnScrollChangedListener +(OnScrollChangedListener)
        + +removePropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        + +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        + +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        + +removeTestProvider +(String)
        + +removeUpdates +(PendingIntent)
        + +replaceExtras
        +  type  +(Intent) in android.content.Intent +
        + +  type  +(Bundle) in android.content.Intent +
        + +reqFiveWayNav +
        + +reqHardKeyboard +
        + +reqKeyboardType +
        + +reqNavigation +
        + +reqTouchScreen +
        + +requestChildRectangleOnScreen +(View, Rect, boolean)
        + +requestLocationUpdates +(String, long, float, PendingIntent)
        + +resetLockedMeta +(long)
        + +ResourceCursorAdapter
        +  android.widget
        + +  ResourceCursorAdapter +(Context, int, Cursor, boolean) constructor
        + +Resources
        + +restartPackage +(String)
        + +restorePicture +(Bundle, File)
        + +ResultReceiver
        + +RingtoneManager
        + +RotateDrawable
        + +ROUTE_BLUETOOTH +
        + +ROUTE_BLUETOOTH_A2DP +
        + +ROUTE_BLUETOOTH_SCO +
        + +rowEdgeFlags +
        + +runTestOnUiThread +(Runnable)
        + + +
        S  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +T +U +V +W +Y +Z + TOP +

        +savePicture +(Bundle, File)
        + +ScaleDrawable
        + +ScaleXSpan
        +  android.text.style
        + +  ScaleXSpan +(Parcel) constructor
        + +SCREEN_BRIGHTNESS_CHANGED +
        + +SCREEN_ORIENTATION_CHANGED +
        + +screenBrightness +
        + +screenOrientation +
        + +Scroller
        + +ScrollingMovementMethod
        + +scrollToBottom
        +  type  +(InstrumentationTestCase, Activity, ViewGroup) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, ViewGroup) in android.test.TouchUtils +
        + +scrollToTop
        +  type  +(InstrumentationTestCase, Activity, ViewGroup) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, ViewGroup) in android.test.TouchUtils +
        + +searchButtonText +
        + +SECONDARY_EMAIL +
        + +SECONDARY_EMAIL_TYPE +
        + +SECONDARY_PHONE +
        + +SECONDARY_PHONE_TYPE +
        + +SectionIndexer
        + +selectAll +
        + +sendExtraCommand +(String, String, Bundle)
        + +Sensor
        + +SENSOR_ACCELEROMETER +
        + +SENSOR_ALL +
        + +SENSOR_LIGHT +
        + +SENSOR_MAGNETIC_FIELD +
        + +SENSOR_MAX +
        + +SENSOR_MIN +
        + +SENSOR_ORIENTATION +
        + +SENSOR_ORIENTATION_RAW +
        + +SENSOR_PROXIMITY +
        + +SENSOR_TEMPERATURE +
        + +SENSOR_TRICORDER +
        + +SensorEvent
        + +SensorEventListener
        + +SensorListener
        + +SensorManager
        + +service +(String, Map<String, String>)
        + +setAllowFileAccess +(boolean)
        + +setBitmap +(int, String, Bitmap)
        + +setBluetoothA2dpOn +(boolean)
        + +setBoolean +(int, String, boolean)
        + +setBuiltInZoomControls +(boolean)
        + +setButton
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(CharSequence, Message) in android.app.AlertDialog +
        + +  type  +(int, CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(int, CharSequence, Message) in android.app.AlertDialog +
        + +setButton2
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(CharSequence, Message) in android.app.AlertDialog +
        + +setButton3
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(CharSequence, Message) in android.app.AlertDialog +
        + +setByte +(int, String, byte)
        + +setCamera +(Camera)
        + +setChar +(int, String, char)
        + +setCharSequence +(int, String, CharSequence)
        + +setClippingEnabled +(boolean)
        + +setCompoundDrawablesWithIntrinsicBounds +(int, int, int, int)
        + +setDouble +(int, String, double)
        + +setDropDownAnchor +(int)
        + +setDropDownWidth +(int)
        + +setExtractedText +(ExtractedText)
        + +setFastScrollEnabled +(boolean)
        + +setFillEnabled +(boolean)
        + +setFloat +(int, String, float)
        + +setFooterDividersEnabled +(boolean)
        + +setHapticFeedbackEnabled +(boolean)
        + +setHeaderDividersEnabled +(boolean)
        + +setImageViewBitmap +(int, Bitmap)
        + +setImeActionLabel +(CharSequence, int)
        + +setImeOptions +(int)
        + +setInexactRepeating +(int, long, long, PendingIntent)
        + +setInputExtras +(int)
        + +setInputMethodMode +(int)
        + +setInputType +(int)
        + +setInt +(int, String, int)
        + +setKeyProgressIncrement +(int)
        + +setListSelection +(int)
        + +setLong +(int, String, long)
        + +setMaxDuration +(int)
        + +setMaxFileSize +(long)
        + +setNetworkAvailable +(boolean)
        + +setOnChronometerTickListener +(OnChronometerTickListener)
        + +setOnClickPendingIntent +(int, PendingIntent)
        + +setOnDoubleTapListener +(OnDoubleTapListener)
        + +setOnEditorActionListener +(OnEditorActionListener)
        + +setOnErrorListener +(OnErrorListener)
        + +setOneShotPreviewCallback +(PreviewCallback)
        + +setOnInfoListener
        +  type  +(OnInfoListener) in android.media.MediaPlayer +
        + +  type  +(OnInfoListener) in android.media.MediaRecorder +
        + +setOnVideoSizeChangedListener +(OnVideoSizeChangedListener)
        + +setOutputFile +(FileDescriptor)
        + +setOutsideTouchable +(boolean)
        + +setPreviewDisplay +(SurfaceHolder)
        + +setPrivateImeOptions +(String)
        + +setRawInputType +(int)
        + +setScrollContainer +(boolean)
        + +setShort +(int, String, short)
        + +setSmoothScrollbarEnabled +(boolean)
        + +setSoftInputMode +(int)
        + +setStaticTransformationsEnabled +(boolean)
        + +setString +(int, String, String)
        + +setTestProviderEnabled +(String, boolean)
        + +setTestProviderLocation +(String, Location)
        + +setTestProviderStatus +(String, int, Bundle, long)
        + +setTextColor +(int, int)
        + +Settings
        + +Settings.Secure
        + +Settings.System
        + +SETTINGS_CLASSNAME +
        + +settingsActivity +
        + +setTouchable +(boolean)
        + +setTouchInterceptor +(OnTouchListener)
        + +setUri +(int, String, Uri)
        + +setUserAgent +(int)
        + +setUserAgentString +(String)
        + +setVideoEncoder +(int)
        + +setVideoFrameRate +(int)
        + +setVideoSize +(int, int)
        + +setVideoSource +(int)
        + +setView +(View, int, int, int, int)
        + +setViewResource +(int)
        + +setVisible +(boolean)
        + +setWindowAnimations +(int)
        + +setWindowLayoutMode +(int, int)
        + +Shape
        + +sharedUserId +
        + +sharedUserLabel
        + in  +android.R.attr +
        + + in  +android.content.pm.PackageInfo +
        + +SHOW_OR_CREATE_CONTACT +
        + +SimpleCursorAdapter
        + +singleLine +
        + +SlidingDrawer
        + +SlidingDrawer.OnDrawerCloseListener
        + +SlidingDrawer.OnDrawerOpenListener
        + +SlidingDrawer.OnDrawerScrollListener
        + +smoothScrollbar +
        + +SmsMessage
        + +Socket
        +  java.net
        + +  Socket +() constructor
        + +  Socket +(String, int) constructor
        + +  Socket +(String, int, InetAddress, int) constructor
        + +  Socket +(Proxy) constructor
        + +  Socket +(SocketImpl) constructor
        + +SOFT_INPUT_ADJUST_PAN +
        + +SOFT_INPUT_ADJUST_RESIZE +
        + +SOFT_INPUT_ADJUST_UNSPECIFIED +
        + +SOFT_INPUT_IS_FORWARD_NAVIGATION +
        + +SOFT_INPUT_MASK_ADJUST +
        + +SOFT_INPUT_MASK_STATE +
        + +SOFT_INPUT_MODE_CHANGED +
        + +SOFT_INPUT_STATE_ALWAYS_HIDDEN +
        + +SOFT_INPUT_STATE_ALWAYS_VISIBLE +
        + +SOFT_INPUT_STATE_HIDDEN +
        + +SOFT_INPUT_STATE_UNCHANGED +
        + +SOFT_INPUT_STATE_UNSPECIFIED +
        + +SOFT_INPUT_STATE_VISIBLE +
        + +softInputMode
        + in  +android.content.pm.ActivityInfo +
        + + in  +android.view.WindowManager.LayoutParams +
        + +sort +(Comparator<? super T>)
        + +SoundPool
        + +SPAN_COMPOSING +
        + +SPAN_INTERMEDIATE +
        + +SPAN_POINT_MARK_MASK +
        + +Spanned
        + +SpanWatcher
        + +SparseIntArray
        + +SQLiteDatabase
        + +startSelectingText +
        + +state_long_pressable +
        + +stopSelectingText +
        + +STREAM_NOTIFICATION +
        + +STRETCH_SPACING_UNIFORM +
        + +StrikethroughSpan
        +  android.text.style
        + +  StrikethroughSpan +(Parcel) constructor
        + +String
        +  java.lang
        + +  String +() constructor
        + +  String +(byte[]) constructor
        + +  String +(byte[], int) constructor
        + +  String +(byte[], int, int) constructor
        + +  String +(byte[], int, int, int) constructor
        + +StyleSpan
        +  android.text.style
        + +  StyleSpan +(Parcel) constructor
        + +SubscriptSpan
        +  android.text.style
        + +  SubscriptSpan +(Parcel) constructor
        + +SuperscriptSpan
        +  android.text.style
        + +  SuperscriptSpan +(Parcel) constructor
        + +switchInputMethod +
        + + +
        T  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +U +V +W +Y +Z + TOP +

        +TelephonyManager
        + +TERTIARY_EMAIL +
        + +TERTIARY_EMAIL_TYPE +
        + +TERTIARY_PHONE +
        + +TERTIARY_PHONE_TYPE +
        + +TestMethod
        +  android.test.suitebuilder
        + +  TestMethod +(String, Class<TestCase>) constructor
        + +  TestMethod +(TestCase) constructor
        + +TestSuiteBuilder
        + +TextAppearanceSpan
        +  android.text.style
        + +  TextAppearanceSpan +(Parcel) constructor
        + +TextKeyListener
        + +TextUtils
        + +TextView
        + +TextView.OnEditorActionListener
        + +TextWatcher
        + +Theme_InputMethod +
        + +Theme_Light_Panel +
        + +Theme_NoDisplay +
        + +Theme_Panel +
        + +thickness +
        + +TimeKeyListener
        + +TimeUtils
        + +title_bar_tall +
        + +topOffset +
        + +toShortString
        +  type  +() in android.graphics.Rect +
        + +  type  +() in android.view.animation.Transformation +
        + +Touch
        + +TouchUtils
        + +Transformation
        + +TransitionDrawable
        +  android.graphics.drawable
        + +  TransitionDrawable +(Drawable[]) constructor
        + +TYPE_APPLICATION_ATTACHED_DIALOG +
        + +TYPE_INPUT_METHOD +
        + +TYPE_INPUT_METHOD_DIALOG +
        + +TypedArray
        + +TypefaceSpan
        +  android.text.style
        + +  TypefaceSpan +(Parcel) constructor
        + + +
        U  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +V +W +Y +Z + TOP +

        +UnderlineSpan
        +  android.text.style
        + +  UnderlineSpan +(Parcel) constructor
        + +UNKNOWN_LENGTH +
        + +unregisterListener
        +  type  +(SensorEventListener) in android.hardware.SensorManager +
        + +  type  +(SensorEventListener, Sensor) in android.hardware.SensorManager +
        + +  type  +(SensorListener) in android.hardware.SensorManager +
        + +  type  +(SensorListener, int) in android.hardware.SensorManager +
        + +update
        +  type  +() in android.widget.PopupWindow +
        + +  type  +(int, int, int, int, boolean) in android.widget.PopupWindow +
        + +UPDATE_DEVICE_STATS +
        + +UpdateAppearance
        + +UpdateLayout
        + +updatePeriodMillis +
        + +UrlInterceptHandler
        + +UrlInterceptRegistry
        + +URLSpan
        +  android.text.style
        + +  URLSpan +(Parcel) constructor
        + +URLUtil
        + +USB_MASS_STORAGE_ENABLED +
        + +USE_GOOGLE_MAIL +
        + +UserDictionary
        + +UserDictionary.Words
        + + +
        V  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +W +Y +Z + TOP +

        +verticalCorrection +
        + +verticalGap +
        + +VideoView_error_text_invalid_progressive_playback +
        + +View
        + +ViewConfiguration
        +  android.view
        + +  ViewConfiguration +() constructor
        + +ViewDebug
        + +ViewDebug.CapturedViewProperty
        + +ViewGroup
        + +ViewParent
        + +ViewTreeObserver
        + +ViewTreeObserver.OnScrollChangedListener
        + +Visibility
        + +VMDebug
        + +voiceLanguage +
        + +voiceLanguageModel +
        + +voiceMaxResults +
        + +voicePromptText +
        + +voiceSearchMode +
        + +VOLUME_NOTIFICATION +
        + + +
        W  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +Y +Z + TOP +

        +WebHistoryItem
        + +WebSettings
        + +WebView
        + +Widget_KeyboardView +
        + +WIFI_MAX_DHCP_RETRY_COUNT +
        + +WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS +
        + +WIFI_MODE_FULL +
        + +WIFI_MODE_SCAN_ONLY +
        + +WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON +
        + +WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY +
        + +WIFI_NUM_OPEN_NETWORKS_KEPT +
        + +WIFI_ON +
        + +WIFI_SLEEP_POLICY +
        + +WIFI_SLEEP_POLICY_DEFAULT +
        + +WIFI_SLEEP_POLICY_NEVER +
        + +WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED +
        + +WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE +
        + +WIFI_WATCHDOG_AP_COUNT +
        + +WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS +
        + +WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED +
        + +WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS +
        + +WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT +
        + +WIFI_WATCHDOG_MAX_AP_CHECKS +
        + +WIFI_WATCHDOG_ON +
        + +WIFI_WATCHDOG_PING_COUNT +
        + +WIFI_WATCHDOG_PING_DELAY_MS +
        + +WIFI_WATCHDOG_PING_TIMEOUT_MS +
        + +WifiManager
        + +Window
        + +windowDisablePreview +
        + +WindowManager.LayoutParams
        + +windowNoDisplay +
        + +windowSoftInputMode +
        + +WRITE_SECURE_SETTINGS +
        + +writeMap +(Map)
        + +writeToParcel
        +  type  +(Parcel, int) in android.content.res.AssetFileDescriptor +
        + +  type  +(Parcel, int) in android.graphics.RectF +
        + +  type  +(Parcel, int) in android.text.Annotation +
        + +  type  +(Parcel, int) in android.text.style.AbsoluteSizeSpan +
        + +  type  +(Parcel, int) in android.text.style.AlignmentSpan.Standard +
        + +  type  +(Parcel, int) in android.text.style.BackgroundColorSpan +
        + +  type  +(Parcel, int) in android.text.style.BulletSpan +
        + +  type  +(Parcel, int) in android.text.style.ForegroundColorSpan +
        + +  type  +(Parcel, int) in android.text.style.LeadingMarginSpan.Standard +
        + +  type  +(Parcel, int) in android.text.style.QuoteSpan +
        + +  type  +(Parcel, int) in android.text.style.RelativeSizeSpan +
        + +  type  +(Parcel, int) in android.text.style.ScaleXSpan +
        + +  type  +(Parcel, int) in android.text.style.StrikethroughSpan +
        + +  type  +(Parcel, int) in android.text.style.StyleSpan +
        + +  type  +(Parcel, int) in android.text.style.SubscriptSpan +
        + +  type  +(Parcel, int) in android.text.style.SuperscriptSpan +
        + +  type  +(Parcel, int) in android.text.style.TextAppearanceSpan +
        + +  type  +(Parcel, int) in android.text.style.TypefaceSpan +
        + +  type  +(Parcel, int) in android.text.style.URLSpan +
        + +  type  +(Parcel, int) in android.text.style.UnderlineSpan +
        + + +
        Y  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +yieldIfContended +()
        + +yieldIfContendedSafely +()
        + + +
        Z  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +Zygote
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/alldiffs_index_changes.html b/docs/html/sdk/api_diff/3/changes/alldiffs_index_changes.html new file mode 100644 index 0000000000000000000000000000000000000000..b35bdb35ce4beb9be9a045dba71a19d8db2e623d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/alldiffs_index_changes.html @@ -0,0 +1,1652 @@ + + + + + + + + + +All Changes Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Differences +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + + +
        A  +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +AbsListView
        + +AbsoluteLayout
        + +AbsoluteSizeSpan
        + +AbsSeekBar
        + +Activity
        + +ActivityInfo
        + +ActivityInstrumentationTestCase
        + +ActivityManager
        + +ADB_ENABLED +
        + +addRequirements +(Predicate<TestMethod>)
        + +AlarmManager
        + +AlertDialog
        + +AlignmentSpan.Standard
        + +android
        + +android.app
        + +android.content
        + +android.content.pm
        + +android.content.res
        + +android.database
        + +android.database.sqlite
        + +android.graphics
        + +android.graphics.drawable
        + +android.graphics.drawable.shapes
        + +android.hardware
        + +android.location
        + +android.media
        + +android.net
        + +android.net.wifi
        + +android.opengl
        + +android.os
        + +android.preference
        + +android.provider
        + +android.telephony
        + +android.telephony.gsm
        + +android.test
        + +android.test.mock
        + +android.test.suitebuilder
        + +android.text
        + +android.text.method
        + +android.text.style
        + +android.util
        + +android.view
        + +android.view.animation
        + +android.webkit
        + +android.widget
        + +ANDROID_ID +
        + +Animation
        + +Annotation
        + +appendEscapedSQLString +(StringBuilder, String)
        + +ArrayAdapter
        + +ArrowKeyMovementMethod
        + +AssetFileDescriptor
        + +AudioManager
        + +AutoCompleteTextView
        + +AutoText
        + +autoText +
        + + +
        B  +A +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +BackgroundColorSpan
        + +BaseKeyListener
        + +Binder
        + +Bitmap
        + +BLUETOOTH_ON +
        + +BroadcastReceiver
        + +Browser
        + +Build
        + +BulletSpan
        + +BUTTON1 +
        + +BUTTON2 +
        + +BUTTON3 +
        + + +
        C  +A +B +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +Camera
        + +Canvas
        + +capitalize +
        + +changeDebugPort +(int)
        + +Character.UnicodeBlock
        + +Chronometer
        + +Class
        + +ClickableSpan
        + +clone +()
        + +Configuration
        + +ConnectivityManager
        + +Contacts.Intents
        + +Contacts.Intents.Insert
        + +Contacts.PeopleColumns
        + +ContentProvider
        + +ContentResolver
        + +Context
        + +Cursor
        + +CursorAdapter
        + +CursorWrapper
        + + +dalvik.system
        + +DATA_ROAMING +
        + +DATA_X +
        + +DATA_Y +
        + +DATA_Z +
        + +DatabaseUtils
        + +Date
        +  java.util
        + +  Date +() constructor
        + +  Date +(int, int, int, int, int, int) constructor
        + +DateKeyListener
        + +DateTimeKeyListener
        + +Debug
        + +DEFAULT_SORT_ORDER
        + in  +android.provider.MediaStore.Images.Media +
        + + in  +android.provider.MediaStore.Video +
        + +DEVICE_PROVISIONED +
        + +DexFile
        + +DialerKeyListener
        + +DialogInterface
        + +DialogPreference
        + +DigitsKeyListener
        + +drag +(ActivityInstrumentationTestCase, float, float, float, float, int)
        + +dragQuarterScreenDown +(ActivityInstrumentationTestCase)
        + +dragQuarterScreenUp +(ActivityInstrumentationTestCase)
        + +dragViewBy +(ActivityInstrumentationTestCase, View, int, int, int)
        + +dragViewTo +(ActivityInstrumentationTestCase, View, int, int, int)
        + +dragViewToBottom
        +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        + +  type  +(InstrumentationTestCase, Activity, View) in android.test.TouchUtils +
        + +dragViewToTop
        +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        + +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        + +dragViewToX +(ActivityInstrumentationTestCase, View, int, int)
        + +dragViewToY +(ActivityInstrumentationTestCase, View, int, int)
        + +Drawable
        + +DynamicDrawableSpan
        + + +
        E  +A +B +C +D +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +editable +
        + +enabled +
        + +Environment
        + + +
        F  +A +B +C +D +E +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +ForegroundColorSpan
        + +forkAndSpecialize +(int, int, int[], boolean, int[][])
        + +forkSystemServer +(int, int, int[], boolean, int[][])
        + +forName +(String)
        + + +
        G  +A +B +C +D +E +F +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +GestureDetector
        +  android.view
        + +  GestureDetector +(OnGestureListener) constructor
        + +  GestureDetector +(OnGestureListener, Handler) constructor
        + +GestureDetector.SimpleOnGestureListener
        + +getClasses +()
        + +getColumnIndex
        +  type  +(String) in android.database.Cursor +
        + +  type  +(String) in android.database.CursorWrapper +
        + +getConstructors +()
        + +getCount +()
        + +getDeclaredClasses +()
        + +getDeclaredConstructors +()
        + +getEdgeSlop +()
        + +getFadingEdgeLength +()
        + +getHandler +()
        + +getInterfaces +()
        + +getItem +(int)
        + +getItemClickListener +()
        + +getItemId +(int)
        + +getItemSelectedListener +()
        + +getMaximumDrawingCacheSize +()
        + +getMinimumFlingVelocity +()
        + +getProxyClass +(ClassLoader, Class<?>)
        + +getScrollBarSize +()
        + +getSensors +()
        + +getSurrogate +(String, Map<String, String>)
        + +getTargetIntent +()
        + +getTouchSlop +()
        + +getUserAgent +()
        + +getWindowTouchSlop +()
        + +getZoomControls +()
        + +Gravity
        + +GridView
        + + +
        H  +A +B +C +D +E +F +G +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +Handler
        + +HTTP_PROXY +
        + + +
        I  +A +B +C +D +E +F +G +H +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +IBinder
        + +ImageSpan
        + +inputMethod +
        + +INSTALL_NON_MARKET_APPS +
        + +Instrumentation
        + +InstrumentationTestCase
        + +Intent
        + +isCookielessProxyUrl +(String)
        + + +java.lang
        + +java.lang.reflect
        + +java.net
        + +java.util
        + +java.util.jar
        + +java.util.logging
        + + +
        K  +A +B +C +D +E +F +G +H +I +J +L +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +KeyCharacterMap
        + +KeyEvent
        + +KeyListener
        + + +
        L  +A +B +C +D +E +F +G +H +I +J +K +M +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +LauncherActivity
        + +LeadingMarginSpan.Standard
        + +Level
        + +LIGHT_NO_MOON +
        + +ListView
        + +Location
        + +LOCATION_PROVIDERS_ALLOWED +
        + +LocationManager
        + +LOGGING_ID +
        + +LogManager
        + +longClickView +(ActivityInstrumentationTestCase, View)
        + +Looper
        + + +
        M  +A +B +C +D +E +F +G +H +I +J +K +L +N +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +Manifest.permission
        + +MaskFilterSpan
        + +MAX_KEYCODE +
        + +MediaPlayer
        + +MediaRecorder
        + +MediaRecorder.OutputFormat
        + +MediaStore
        + +MediaStore.Audio.AlbumColumns
        + +MediaStore.Audio.Media
        + +MediaStore.Images.Media
        + +MediaStore.Video
        + +MediaStore.Video.VideoColumns
        + +Menu
        + +MetaKeyKeyListener
        + +MockPackageManager
        + +MotionEvent
        + +MovementMethod
        + +MultiTapKeyListener
        + + +
        N  +A +B +C +D +E +F +G +H +I +J +K +L +M +O +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +NETWORK_PREFERENCE +
        + +NetworkInfo
        + +NUM_STREAMS +
        + +numeric +
        + + +
        O  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +P +Q +R +S +T +U +V +W +Y +Z + TOP +

        +onGlobalFocusChanged +(View, View)
        + +onRestoreInstanceState +(Parcelable)
        + +onSaveInstanceState +()
        + +OrientationListener
        + + +
        P  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +Q +R +S +T +U +V +W +Y +Z + TOP +

        +Pack200.Packer
        + +Pack200.Unpacker
        + +PackageInfo
        + +PackageManager
        + +Parcel
        + +ParcelFileDescriptor
        + +PARENTAL_CONTROL_ENABLED +
        + +PARENTAL_CONTROL_LAST_UPDATE +
        + +PARENTAL_CONTROL_REDIRECT_URL +
        + +parse +(String)
        + +password +
        + +PendingIntent
        + +phoneNumber +
        + +PhoneNumberUtils
        + +playSoundEffect +(int)
        + +PopupWindow
        + +PopupWindow.OnDismissListener
        + +prepare +()
        + +ProgressBar
        + +ProviderTestCase
        + +Proxy
        + + +
        Q  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +R +S +T +U +V +W +Y +Z + TOP +

        +QuoteSpan
        + +QwertyKeyListener
        + + +
        R  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +S +T +U +V +W +Y +Z + TOP +

        +R.attr
        + +R.drawable
        + +R.id
        + +R.string
        + +R.style
        + +RasterizerSpan
        + +RAW_DATA_INDEX +
        + +RAW_DATA_X +
        + +RAW_DATA_Y +
        + +RAW_DATA_Z +
        + +readHashMap +(ClassLoader)
        + +readMap +(Map, ClassLoader)
        + +Rect
        + +RectF
        + +registerListener
        +  type  +(SensorListener, int) in android.hardware.SensorManager +
        + +  type  +(SensorListener, int, int) in android.hardware.SensorManager +
        + +RelativeSizeSpan
        + +RemoteViews
        + +RemoteViews.ActionException
        + +ResourceCursorAdapter
        + +Resources
        + +RingtoneManager
        + +RotateDrawable
        + +ROUTE_BLUETOOTH +
        + + +
        S  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +T +U +V +W +Y +Z + TOP +

        +ScaleDrawable
        + +ScaleXSpan
        + +Scroller
        + +ScrollingMovementMethod
        + +scrollToBottom +(ActivityInstrumentationTestCase, ViewGroup)
        + +scrollToTop +(ActivityInstrumentationTestCase, ViewGroup)
        + +searchButtonText +
        + +SENSOR_ACCELEROMETER +
        + +SENSOR_ALL +
        + +SENSOR_LIGHT +
        + +SENSOR_MAGNETIC_FIELD +
        + +SENSOR_MAX +
        + +SENSOR_MIN +
        + +SENSOR_ORIENTATION +
        + +SENSOR_ORIENTATION_RAW +
        + +SENSOR_PROXIMITY +
        + +SENSOR_TEMPERATURE +
        + +SENSOR_TRICORDER +
        + +SensorListener
        + +SensorManager
        + +service +(String, Map<String, String>)
        + +setButton
        +  type  +(int, CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(int, CharSequence, Message) in android.app.AlertDialog +
        + +setButton2
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(CharSequence, Message) in android.app.AlertDialog +
        + +setButton3
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        + +  type  +(CharSequence, Message) in android.app.AlertDialog +
        + +setPreviewDisplay +(SurfaceHolder)
        + +Settings
        + +Settings.System
        + +SETTINGS_CLASSNAME +
        + +setUserAgent +(int)
        + +Shape
        + +SimpleCursorAdapter
        + +singleLine +
        + +SmsMessage
        + +Socket
        +  java.net
        + +  Socket +() constructor
        + +  Socket +(String, int) constructor
        + +  Socket +(String, int, InetAddress, int) constructor
        + +  Socket +(Proxy) constructor
        + +  Socket +(SocketImpl) constructor
        + +SoundPool
        + +Spanned
        + +SpanWatcher
        + +SparseIntArray
        + +SQLiteDatabase
        + +StrikethroughSpan
        + +String
        +  java.lang
        + +  String +() constructor
        + +  String +(byte[]) constructor
        + +  String +(byte[], int) constructor
        + +  String +(byte[], int, int) constructor
        + +  String +(byte[], int, int, int) constructor
        + +StyleSpan
        + +SubscriptSpan
        + +SuperscriptSpan
        + + +
        T  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +U +V +W +Y +Z + TOP +

        +TelephonyManager
        + +TestMethod
        + +TestSuiteBuilder
        + +TextAppearanceSpan
        + +TextKeyListener
        + +TextUtils
        + +TextView
        + +TextWatcher
        + +TimeKeyListener
        + +TimeUtils
        + +Touch
        + +TouchUtils
        + +Transformation
        + +TransitionDrawable
        + +TypedArray
        + +TypefaceSpan
        + + +
        U  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +V +W +Y +Z + TOP +

        +UnderlineSpan
        + +unregisterListener
        +  type  +(SensorListener) in android.hardware.SensorManager +
        + +  type  +(SensorListener, int) in android.hardware.SensorManager +
        + +UpdateLayout
        + +UrlInterceptHandler
        + +UrlInterceptRegistry
        + +URLSpan
        + +URLUtil
        + +USB_MASS_STORAGE_ENABLED +
        + +USE_GOOGLE_MAIL +
        + + +
        V  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +W +Y +Z + TOP +

        +View
        + +ViewConfiguration
        +  android.view
        + +  ViewConfiguration +() constructor
        + +ViewDebug
        + +ViewGroup
        + +ViewParent
        + +ViewTreeObserver
        + +VMDebug
        + + +
        W  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +Y +Z + TOP +

        +WebHistoryItem
        + +WebSettings
        + +WebView
        + +WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON +
        + +WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY +
        + +WIFI_NUM_OPEN_NETWORKS_KEPT +
        + +WIFI_ON +
        + +WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE +
        + +WIFI_WATCHDOG_AP_COUNT +
        + +WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS +
        + +WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED +
        + +WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS +
        + +WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT +
        + +WIFI_WATCHDOG_MAX_AP_CHECKS +
        + +WIFI_WATCHDOG_ON +
        + +WIFI_WATCHDOG_PING_COUNT +
        + +WIFI_WATCHDOG_PING_DELAY_MS +
        + +WIFI_WATCHDOG_PING_TIMEOUT_MS +
        + +WifiManager
        + +Window
        + +WindowManager.LayoutParams
        + +writeMap +(Map)
        + + +
        Y  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +yieldIfContended +()
        + + +
        Z  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Y + TOP +

        +Zygote
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/alldiffs_index_removals.html b/docs/html/sdk/api_diff/3/changes/alldiffs_index_removals.html new file mode 100644 index 0000000000000000000000000000000000000000..662b26690d2e3e6b75b21ddcad7e35e18b2a89ff --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/alldiffs_index_removals.html @@ -0,0 +1,78 @@ + + + + + + + + + +All Removals Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Differences +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + + +
        C  +N + TOP +

        +CATEGORY_GADGET +
        + + +
        N  +C + TOP +

        +NetworkInfo +(int) constructor
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.Manifest.permission.html b/docs/html/sdk/api_diff/3/changes/android.Manifest.permission.html new file mode 100644 index 0000000000000000000000000000000000000000..76591022179eac5bd96814e55d605380cdaaaf48 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.Manifest.permission.html @@ -0,0 +1,151 @@ + + + + + + + + + +android.Manifest.permission + + + + + + + + + + +
        +
        +
        +

        +Class android.Manifest.permission +

        + + + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String BIND_APPWIDGET +  
        + + String BIND_INPUT_METHOD +  
        + + String MOUNT_FORMAT_FILESYSTEMS +  
        + + String UPDATE_DEVICE_STATS +  
        + + String WRITE_SECURE_SETTINGS +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.R.attr.html b/docs/html/sdk/api_diff/3/changes/android.R.attr.html new file mode 100644 index 0000000000000000000000000000000000000000..7df16a12132990b2ce887b815e93388852171182 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.R.attr.html @@ -0,0 +1,739 @@ + + + + + + + + + +android.R.attr + + + + + + + + + + +
        +
        +
        +

        +Class android.R.attr +

        + + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int allowSingleTap +  
        + + int animateOnClick +  
        + + int backgroundDimEnabled +  
        + + int bottomOffset +  
        + + int candidatesTextStyleSpans +  
        + + int codes +  
        + + int configure +  
        + + int content +  
        + + int dropDownAnchor +  
        + + int dropDownWidth +  
        + + int editorExtras +  
        + + int fastScrollEnabled +  
        + + int fillEnabled +  
        + + int footerDividersEnabled +  
        + + int handle +  
        + + int hapticFeedbackEnabled +  
        + + int headerDividersEnabled +  
        + + int horizontalGap +  
        + + int iconPreview +  
        + + int imeActionId +  
        + + int imeActionLabel +  
        + + int imeExtractEnterAnimation +  
        + + int imeExtractExitAnimation +  
        + + int imeFullscreenBackground +  
        + + int imeOptions +  
        + + int initialLayout +  
        + + int innerRadius +  
        + + int inputType +  
        + + int isDefault +  
        + + int isModifier +  
        + + int isRepeatable +  
        + + int isScrollContainer +  
        + + int isSticky +  
        + + int keyBackground +  
        + + int keyEdgeFlags +  
        + + int keyHeight +  
        + + int keyIcon +  
        + + int keyLabel +  
        + + int keyOutputText +  
        + + int keyPreviewHeight +  
        + + int keyPreviewLayout +  
        + + int keyPreviewOffset +  
        + + int keyTextColor +  
        + + int keyTextSize +  
        + + int keyWidth +  
        + + int keyboardMode +  
        + + int labelTextSize +  
        + + int noHistory +  
        + + int popupCharacters +  
        + + int popupKeyboard +  
        + + int popupLayout +  
        + + int privateImeOptions +  
        + + int reqFiveWayNav +  
        + + int reqHardKeyboard +  
        + + int reqKeyboardType +  
        + + int reqNavigation +  
        + + int reqTouchScreen +  
        + + int rowEdgeFlags +  
        + + int settingsActivity +  
        + + int sharedUserLabel +  
        + + int smoothScrollbar +  
        + + int state_long_pressable +  
        + + int thickness +  
        + + int topOffset +  
        + + int updatePeriodMillis +  
        + + int verticalCorrection +  
        + + int verticalGap +  
        + + int voiceLanguage +  
        + + int voiceLanguageModel +  
        + + int voiceMaxResults +  
        + + int voicePromptText +  
        + + int voiceSearchMode +  
        + + int windowDisablePreview +  
        + + int windowNoDisplay +  
        + + int windowSoftInputMode +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Fields +
        + + int autoText +Now deprecated.
        +
         
        + + int capitalize +Now deprecated.
        +
         
        + + int editable +Now deprecated.
        +
         
        + + int enabled +Now deprecated.
        +
         
        + + int inputMethod +Now deprecated.
        +
         
        + + int numeric +Now deprecated.
        +
         
        + + int password +Now deprecated.
        +
         
        + + int phoneNumber +Now deprecated.
        +
         
        + + int searchButtonText +Now deprecated.
        +
         
        + + int singleLine +Now deprecated.
        +
         
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.R.drawable.html b/docs/html/sdk/api_diff/3/changes/android.R.drawable.html new file mode 100644 index 0000000000000000000000000000000000000000..fe046dd7370f192f7a9f62071bced8518b0f344a --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.R.drawable.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.R.drawable + + + + + + + + + + +
        +
        +
        +

        +Class android.R.drawable +

        + + + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int dark_header +  
        + + int ic_btn_speak_now +  
        + + int title_bar_tall +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.R.id.html b/docs/html/sdk/api_diff/3/changes/android.R.id.html new file mode 100644 index 0000000000000000000000000000000000000000..d30fc1da3b7f0cbcfe7ab3accc721a0f2a46a7ec --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.R.id.html @@ -0,0 +1,221 @@ + + + + + + + + + +android.R.id + + + + + + + + + + +
        +
        +
        +

        +Class android.R.id +

        + + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int addToDictionary +  
        + + int candidatesArea +  
        + + int closeButton +  
        + + int copy +  
        + + int copyUrl +  
        + + int cut +  
        + + int extractArea +  
        + + int inputArea +  
        + + int inputExtractEditText +  
        + + int keyboardView +  
        + + int paste +  
        + + int selectAll +  
        + + int startSelectingText +  
        + + int stopSelectingText +  
        + + int switchInputMethod +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.R.string.html b/docs/html/sdk/api_diff/3/changes/android.R.string.html new file mode 100644 index 0000000000000000000000000000000000000000..5d18ffa187c6fab53f84570109a3bff9c1b311ba --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.R.string.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.R.string + + + + + + + + + + +
        +
        +
        +

        +Class android.R.string +

        + + + +

        + + + + + + + + + + + + +
        Added Fields +
        + + int VideoView_error_text_invalid_progressive_playback +  
        + + int dialog_alert_title +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.R.style.html b/docs/html/sdk/api_diff/3/changes/android.R.style.html new file mode 100644 index 0000000000000000000000000000000000000000..726bab9fb2b485d3ce1717ed3573bb36da1db73c --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.R.style.html @@ -0,0 +1,151 @@ + + + + + + + + + +android.R.style + + + + + + + + + + +
        +
        +
        +

        +Class android.R.style +

        + + + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int Theme_InputMethod +  
        + + int Theme_Light_Panel +  
        + + int Theme_NoDisplay +  
        + + int Theme_Panel +  
        + + int Widget_KeyboardView +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.app.Activity.html b/docs/html/sdk/api_diff/3/changes/android.app.Activity.html new file mode 100644 index 0000000000000000000000000000000000000000..7ff5871e76ce211a01b0e00b2c48e8cbff22b95e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.app.Activity.html @@ -0,0 +1,151 @@ + + + + + + + + + +android.app.Activity + + + + + + + + + + +
        +
        +
        +

        +Class android.app.Activity +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void closeContextMenu() +  
        + + boolean hasWindowFocus() +  
        + + void onUserInteraction() +  
        + + void onUserLeaveHint() +  
        + + void setVisible(boolean) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.app.ActivityManager.html b/docs/html/sdk/api_diff/3/changes/android.app.ActivityManager.html new file mode 100644 index 0000000000000000000000000000000000000000..bd473fb8a393b8727c665910613e5f4bee754a02 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.app.ActivityManager.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.app.ActivityManager + + + + + + + + + + +
        +
        +
        +

        +Class android.app.ActivityManager +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + ConfigurationInfo getDeviceConfigurationInfo() +  
        + + List<RunningAppProcessInfo> getRunningAppProcesses() +  
        + + void restartPackage(String) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.app.AlarmManager.html b/docs/html/sdk/api_diff/3/changes/android.app.AlarmManager.html new file mode 100644 index 0000000000000000000000000000000000000000..b8280f2fc9b60c1c71c698df542502ad920ba97f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.app.AlarmManager.html @@ -0,0 +1,166 @@ + + + + + + + + + +android.app.AlarmManager + + + + + + + + + + +
        +
        +
        +

        +Class android.app.AlarmManager +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void setInexactRepeating(int, long, long, PendingIntent) +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + long INTERVAL_DAY +  
        + + long INTERVAL_FIFTEEN_MINUTES +  
        + + long INTERVAL_HALF_DAY +  
        + + long INTERVAL_HALF_HOUR +  
        + + long INTERVAL_HOUR +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.app.AlertDialog.html b/docs/html/sdk/api_diff/3/changes/android.app.AlertDialog.html new file mode 100644 index 0000000000000000000000000000000000000000..bb8cdb1624fe566c9fa4d7d4fe4c796d5aa90ce5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.app.AlertDialog.html @@ -0,0 +1,219 @@ + + + + + + + + + +android.app.AlertDialog + + + + + + + + + + +
        +
        +
        +

        +Class android.app.AlertDialog +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + Button getButton(int) +  
        + + ListView getListView() +  
        + + void setButton(CharSequence, OnClickListener) +  
        + + void setButton(CharSequence, Message) +  
        + + void setView(View, int, int, int, int) +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Methods +
        + + void setButton(int, CharSequence, OnClickListener) + +Change in signature from (CharSequence, OnClickListener) to (int, CharSequence, OnClickListener).
        +
         
        + + void setButton(int, CharSequence, Message) + +Change in signature from (CharSequence, Message) to (int, CharSequence, Message).
        +
         
        + + void setButton2(CharSequence, OnClickListener) + +Now deprecated.
        +
         
        + + void setButton2(CharSequence, Message) + +Now deprecated.
        +
         
        + + void setButton3(CharSequence, OnClickListener) + +Now deprecated.
        +
         
        + + void setButton3(CharSequence, Message) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.app.Instrumentation.html b/docs/html/sdk/api_diff/3/changes/android.app.Instrumentation.html new file mode 100644 index 0000000000000000000000000000000000000000..b6f26a6df9621e43d0ea2cecdd4a9f7f568da769 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.app.Instrumentation.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.app.Instrumentation + + + + + + + + + + +
        +
        +
        +

        +Class android.app.Instrumentation +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void callActivityOnUserLeaving(Activity) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.app.LauncherActivity.html b/docs/html/sdk/api_diff/3/changes/android.app.LauncherActivity.html new file mode 100644 index 0000000000000000000000000000000000000000..60f7f29a6071cd519b2980a69e207be2e90e5c48 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.app.LauncherActivity.html @@ -0,0 +1,148 @@ + + + + + + + + + +android.app.LauncherActivity + + + + + + + + + + +
        +
        +
        +

        +Class android.app.LauncherActivity +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + Intent intentForPosition(int) +  
        + + List<ListItem> makeListItems() +  
        +  +

        + + + + + + + + + +
        Changed Methods +
        + + Intent getTargetIntent() + +Changed from abstract to non-abstract. +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.app.PendingIntent.html b/docs/html/sdk/api_diff/3/changes/android.app.PendingIntent.html new file mode 100644 index 0000000000000000000000000000000000000000..6155508fcd817c1de2c19128dcea1f5a0bbbdc8f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.app.PendingIntent.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.app.PendingIntent + + + + + + + + + + +
        +
        +
        +

        +Class android.app.PendingIntent +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + int FLAG_UPDATE_CURRENT +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.BroadcastReceiver.html b/docs/html/sdk/api_diff/3/changes/android.content.BroadcastReceiver.html new file mode 100644 index 0000000000000000000000000000000000000000..bd8cc8ccadb67371baa177d8388beb14f468fab0 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.BroadcastReceiver.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.content.BroadcastReceiver + + + + + + + + + + +
        +
        +
        +

        +Class android.content.BroadcastReceiver +

        + + +

        + + + + + + + + +
        Added Methods +
        + + IBinder peekService(Context, Intent) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.ContentProvider.html b/docs/html/sdk/api_diff/3/changes/android.content.ContentProvider.html new file mode 100644 index 0000000000000000000000000000000000000000..c6de3260516609b243cd697b9a897f73472c7405 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.ContentProvider.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.content.ContentProvider + + + + + + + + + + +
        +
        +
        +

        +Class android.content.ContentProvider +

        + + +

        + + + + + + + + +
        Added Methods +
        + + AssetFileDescriptor openAssetFile(Uri, String) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.ContentResolver.html b/docs/html/sdk/api_diff/3/changes/android.content.ContentResolver.html new file mode 100644 index 0000000000000000000000000000000000000000..2101198a7f040ce538cfe71feb74cf12f57ac7b2 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.ContentResolver.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.content.ContentResolver + + + + + + + + + + +
        +
        +
        +

        +Class android.content.ContentResolver +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + AssetFileDescriptor openAssetFileDescriptor(Uri, String) +  
        + + OutputStream openOutputStream(Uri, String) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.Context.html b/docs/html/sdk/api_diff/3/changes/android.content.Context.html new file mode 100644 index 0000000000000000000000000000000000000000..ac3d99da74f21940151516b6b5b2698282623b16 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.Context.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.content.Context + + + + + + + + + + +
        +
        +
        +

        +Class android.content.Context +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + String INPUT_METHOD_SERVICE +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.DialogInterface.html b/docs/html/sdk/api_diff/3/changes/android.content.DialogInterface.html new file mode 100644 index 0000000000000000000000000000000000000000..17dd651368bccc595c7e0ff9531933fac6ed0197 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.DialogInterface.html @@ -0,0 +1,172 @@ + + + + + + + + + +android.content.DialogInterface + + + + + + + + + + +
        +
        +
        +

        +Interface android.content.DialogInterface +

        + + + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int BUTTON_NEGATIVE +  
        + + int BUTTON_NEUTRAL +  
        + + int BUTTON_POSITIVE +  
        +  +

        + + + + + + + + + + + + + + + + + + + +
        Changed Fields +
        + + int BUTTON1 +Now deprecated.
        +
         
        + + int BUTTON2 +Now deprecated.
        +
         
        + + int BUTTON3 +Now deprecated.
        +
         
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.Intent.html b/docs/html/sdk/api_diff/3/changes/android.content.Intent.html new file mode 100644 index 0000000000000000000000000000000000000000..edb02387b0aa9b095216853d7b5b497e1fd658ab --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.Intent.html @@ -0,0 +1,251 @@ + + + + + + + + + +android.content.Intent + + + + + + + + + + +
        +
        +
        +

        +Class android.content.Intent +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + Intent replaceExtras(Intent) +  
        + + Intent replaceExtras(Bundle) +  
        +  + +

        + + + + + + + + +
        Removed Fields +
        + + String CATEGORY_GADGET +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String ACTION_INPUT_METHOD_CHANGED +  
        + + String ACTION_MEDIA_CHECKING +  
        + + String ACTION_MEDIA_NOFS +  
        + + String ACTION_PACKAGE_DATA_CLEARED +  
        + + String ACTION_PACKAGE_REPLACED +  
        + + String ACTION_SEARCH_LONG_PRESS +  
        + + String ACTION_SYSTEM_TUTORIAL +  
        + + String ACTION_USER_PRESENT +  
        + + String CATEGORY_INFO +  
        + + String EXTRA_DATA_REMOVED +  
        + + String EXTRA_REPLACING +  
        + + int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET +  
        + + int FLAG_ACTIVITY_NO_USER_ACTION +  
        + + int FLAG_ACTIVITY_REORDER_TO_FRONT +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.pm.ActivityInfo.html b/docs/html/sdk/api_diff/3/changes/android.content.pm.ActivityInfo.html new file mode 100644 index 0000000000000000000000000000000000000000..5c62f6b769d092a0dbaac63ddfa6a679c4c2638d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.pm.ActivityInfo.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.content.pm.ActivityInfo + + + + + + + + + + +
        +
        +
        +

        +Class android.content.pm.ActivityInfo +

        + + + +

        + + + + + + + + + + + + +
        Added Fields +
        + + int FLAG_NO_HISTORY +  
        + + int softInputMode +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.pm.PackageInfo.html b/docs/html/sdk/api_diff/3/changes/android.content.pm.PackageInfo.html new file mode 100644 index 0000000000000000000000000000000000000000..b360d7c2bba27cc04947c3aaaa3345c3770e3607 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.pm.PackageInfo.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.content.pm.PackageInfo + + + + + + + + + + +
        +
        +
        +

        +Class android.content.pm.PackageInfo +

        + + + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + ConfigurationInfo[] configPreferences +  
        + + String sharedUserId +  
        + + int sharedUserLabel +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.pm.PackageManager.html b/docs/html/sdk/api_diff/3/changes/android.content.pm.PackageManager.html new file mode 100644 index 0000000000000000000000000000000000000000..efd37c54f3b177f39c8714f756a7fb1571c0879e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.pm.PackageManager.html @@ -0,0 +1,166 @@ + + + + + + + + + +android.content.pm.PackageManager + + + + + + + + + + +
        +
        +
        +

        +Class android.content.pm.PackageManager +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + Intent getLaunchIntentForPackage(String) +  
        + + String[] getSystemSharedLibraryNames() +  
        + + boolean isSafeMode() +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int GET_CONFIGURATIONS +  
        + + int GET_UNINSTALLED_PACKAGES +  
        + + int INSTALL_FAILED_CONFLICTING_PROVIDER +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.res.AssetFileDescriptor.html b/docs/html/sdk/api_diff/3/changes/android.content.res.AssetFileDescriptor.html new file mode 100644 index 0000000000000000000000000000000000000000..458a70a74ecf53d6515f234f16f7a96edfbc339f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.res.AssetFileDescriptor.html @@ -0,0 +1,174 @@ + + + + + + + + + +android.content.res.AssetFileDescriptor + + + + + + + + + + +
        +
        +
        +

        +Class android.content.res.AssetFileDescriptor +

        +

        Added interface android.os.Parcelable.
        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + FileInputStream createInputStream() +  
        + + FileOutputStream createOutputStream() +  
        + + int describeContents() +  
        + + long getDeclaredLength() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + + + + + + + + + + + + +
        Added Fields +
        + + Creator CREATOR +  
        + + long UNKNOWN_LENGTH +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.res.Configuration.html b/docs/html/sdk/api_diff/3/changes/android.content.res.Configuration.html new file mode 100644 index 0000000000000000000000000000000000000000..3b8f943aceb7a117ce4a827810f39f68aae4598f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.res.Configuration.html @@ -0,0 +1,144 @@ + + + + + + + + + +android.content.res.Configuration + + + + + + + + + + +
        +
        +
        +

        +Class android.content.res.Configuration +

        + + + +

        + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int HARDKEYBOARDHIDDEN_NO +  
        + + int HARDKEYBOARDHIDDEN_UNDEFINED +  
        + + int HARDKEYBOARDHIDDEN_YES +  
        + + int hardKeyboardHidden +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.res.Resources.html b/docs/html/sdk/api_diff/3/changes/android.content.res.Resources.html new file mode 100644 index 0000000000000000000000000000000000000000..7fde1f9833109bd47901627610ddc0acd5e51ce1 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.res.Resources.html @@ -0,0 +1,151 @@ + + + + + + + + + +android.content.res.Resources + + + + + + + + + + +
        +
        +
        +

        +Class android.content.res.Resources +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean getBoolean(int) +  
        + + float getFraction(int, int, int) +  
        + + InputStream openRawResource(int, TypedValue) +  
        + + void parseBundleExtra(String, AttributeSet, Bundle) +  
        + + void parseBundleExtras(XmlResourceParser, Bundle) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.content.res.TypedArray.html b/docs/html/sdk/api_diff/3/changes/android.content.res.TypedArray.html new file mode 100644 index 0000000000000000000000000000000000000000..f1336fc7d7ed93bc2fa53cfcb43d7f7a2348a8b8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.content.res.TypedArray.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.content.res.TypedArray + + + + + + + + + + +
        +
        +
        +

        +Class android.content.res.TypedArray +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getLayoutDimension(int, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.database.Cursor.html b/docs/html/sdk/api_diff/3/changes/android.database.Cursor.html new file mode 100644 index 0000000000000000000000000000000000000000..020402a4c71416f3a9985d1f19934b6c0bb6f0ef --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.database.Cursor.html @@ -0,0 +1,126 @@ + + + + + + + + + +android.database.Cursor + + + + + + + + + + +
        +
        +
        +

        +Interface android.database.Cursor +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + int getColumnIndex(String) + +Change from deprecated to undeprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.database.CursorWrapper.html b/docs/html/sdk/api_diff/3/changes/android.database.CursorWrapper.html new file mode 100644 index 0000000000000000000000000000000000000000..3a7675d57da6e02819c003bc3816567f8fc365da --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.database.CursorWrapper.html @@ -0,0 +1,126 @@ + + + + + + + + + +android.database.CursorWrapper + + + + + + + + + + +
        +
        +
        +

        +Class android.database.CursorWrapper +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + int getColumnIndex(String) + +Change from deprecated to undeprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.database.DatabaseUtils.html b/docs/html/sdk/api_diff/3/changes/android.database.DatabaseUtils.html new file mode 100644 index 0000000000000000000000000000000000000000..114beaeeee62320019ce4591ed7c41981f765130 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.database.DatabaseUtils.html @@ -0,0 +1,126 @@ + + + + + + + + + +android.database.DatabaseUtils + + + + + + + + + + +
        +
        +
        +

        +Class android.database.DatabaseUtils +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + void appendEscapedSQLString(StringBuilder, String) + +Change from deprecated to undeprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.database.sqlite.SQLiteDatabase.html b/docs/html/sdk/api_diff/3/changes/android.database.sqlite.SQLiteDatabase.html new file mode 100644 index 0000000000000000000000000000000000000000..cd59c1b854310edc0a4afde3c6f957669e967353 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.database.sqlite.SQLiteDatabase.html @@ -0,0 +1,141 @@ + + + + + + + + + +android.database.sqlite.SQLiteDatabase + + + + + + + + + + +
        +
        +
        +

        +Class android.database.sqlite.SQLiteDatabase +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean yieldIfContendedSafely() +  
        +  +

        + + + + + + + + + +
        Changed Methods +
        + + boolean yieldIfContended() + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.Bitmap.html b/docs/html/sdk/api_diff/3/changes/android.graphics.Bitmap.html new file mode 100644 index 0000000000000000000000000000000000000000..f6ddc29c10bfb54c9584eae29af1f36bf01cc133 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.Bitmap.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.graphics.Bitmap + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.Bitmap +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void copyPixelsFromBuffer(Buffer) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.Canvas.html b/docs/html/sdk/api_diff/3/changes/android.graphics.Canvas.html new file mode 100644 index 0000000000000000000000000000000000000000..cf8ceef7ab5fb7f989b9c8aefe30e4596d0dd2b1 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.Canvas.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.graphics.Canvas + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.Canvas +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void drawBitmap(int[], int, int, float, float, int, int, boolean, Paint) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.Rect.html b/docs/html/sdk/api_diff/3/changes/android.graphics.Rect.html new file mode 100644 index 0000000000000000000000000000000000000000..1c0b1f342d377a324d5a5597e0beca32f92b3ae7 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.Rect.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.graphics.Rect + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.Rect +

        + + +

        + + + + + + + + +
        Added Methods +
        + + String toShortString() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.RectF.html b/docs/html/sdk/api_diff/3/changes/android.graphics.RectF.html new file mode 100644 index 0000000000000000000000000000000000000000..4e9b91b2a2ed36f33ece73442a5648c70f1df6a3 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.RectF.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.graphics.RectF + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.RectF +

        +

        Added interface android.os.Parcelable.
        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + void readFromParcel(Parcel) +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + + + + + + + + +
        Added Fields +
        + + Creator CREATOR +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.Drawable.html b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.Drawable.html new file mode 100644 index 0000000000000000000000000000000000000000..faa70b96da44905538040325aedc4b516b0ee9f8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.Drawable.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.graphics.drawable.Drawable + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.drawable.Drawable +

        + + +

        + + + + + + + + +
        Added Methods +
        + + Drawable mutate() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.RotateDrawable.html b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.RotateDrawable.html new file mode 100644 index 0000000000000000000000000000000000000000..8cffe1e0bdb9a038e8f325a86c9caca6b88a70b1 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.RotateDrawable.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.graphics.drawable.RotateDrawable + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.drawable.RotateDrawable +

        + + +

        + + + + + + + + +
        Added Methods +
        + + Drawable getDrawable() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.ScaleDrawable.html b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.ScaleDrawable.html new file mode 100644 index 0000000000000000000000000000000000000000..529f38026ebef83be3f132135d71ed22db5017e0 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.ScaleDrawable.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.graphics.drawable.ScaleDrawable + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.drawable.ScaleDrawable +

        + + +

        + + + + + + + + +
        Added Methods +
        + + Drawable getDrawable() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.TransitionDrawable.html b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.TransitionDrawable.html new file mode 100644 index 0000000000000000000000000000000000000000..d7dc8eafcf3c180b358fa272bfb117ecba0f9661 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.TransitionDrawable.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.graphics.drawable.TransitionDrawable + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.drawable.TransitionDrawable +

        + +

        + + + + + + + + +
        Added Constructors +
        + + TransitionDrawable(Drawable[]) +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.shapes.Shape.html b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.shapes.Shape.html new file mode 100644 index 0000000000000000000000000000000000000000..836aa92159130bad7590c72dc6f80df6c6cda02f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.graphics.drawable.shapes.Shape.html @@ -0,0 +1,128 @@ + + + + + + + + + +android.graphics.drawable.shapes.Shape + + + + + + + + + + +
        +
        +
        +

        +Class android.graphics.drawable.shapes.Shape +

        +

        Added interface java.lang.Cloneable.
        + + +

        + + + + + + + + + +
        Changed Methods +
        + + Shape clone() + +Change in return type from Object to Shape.
        + Method was inherited from java.lang.Object, but is now defined locally. Change of visibility from protected to public.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.hardware.Camera.html b/docs/html/sdk/api_diff/3/changes/android.hardware.Camera.html new file mode 100644 index 0000000000000000000000000000000000000000..b7a0dd37a1222fa0cfb16f1025559e322b9ad00c --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.hardware.Camera.html @@ -0,0 +1,141 @@ + + + + + + + + + +android.hardware.Camera + + + + + + + + + + +
        +
        +
        +

        +Class android.hardware.Camera +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void setOneShotPreviewCallback(PreviewCallback) +  
        +  +

        + + + + + + + + + +
        Changed Methods +
        + + void setPreviewDisplay(SurfaceHolder) + +Change in exceptions thrown from no exceptions to java.io.IOException.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.hardware.SensorListener.html b/docs/html/sdk/api_diff/3/changes/android.hardware.SensorListener.html new file mode 100644 index 0000000000000000000000000000000000000000..9b63571fcf52ceb6b84550a6c6bab014f4940edb --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.hardware.SensorListener.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.hardware.SensorListener + + + + + + + + + + +
        +
        +
        +

        +Interface android.hardware.SensorListener +

        +

        Now deprecated.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.hardware.SensorManager.html b/docs/html/sdk/api_diff/3/changes/android.hardware.SensorManager.html new file mode 100644 index 0000000000000000000000000000000000000000..e42eebaf21f9df99f753d8ec19e719b5c3265fb8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.hardware.SensorManager.html @@ -0,0 +1,473 @@ + + + + + + + + + +android.hardware.SensorManager + + + + + + + + + + +
        +
        +
        +

        +Class android.hardware.SensorManager +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + Sensor getDefaultSensor(int) +  
        + + float getInclination(float[]) +  
        + + float[] getOrientation(float[], float[]) +  
        + + boolean getRotationMatrix(float[], float[], float[], float[]) +  
        + + List<Sensor> getSensorList(int) +  
        + + boolean registerListener(SensorEventListener, Sensor, int) +  
        + + boolean registerListener(SensorEventListener, Sensor, int, Handler) +  
        + + boolean remapCoordinateSystem(float[], int, int, float[]) +  
        + + void unregisterListener(SensorEventListener) +  
        + + void unregisterListener(SensorEventListener, Sensor) +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Methods +
        + + int getSensors() + +Now deprecated.
        +
         
        + + boolean registerListener(SensorListener, int) + +Now deprecated.
        +
         
        + + boolean registerListener(SensorListener, int, int) + +Now deprecated.
        +
         
        + + void unregisterListener(SensorListener) + +Now deprecated.
        +
         
        + + void unregisterListener(SensorListener, int) + +Now deprecated.
        +
         
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int AXIS_MINUS_X +  
        + + int AXIS_MINUS_Y +  
        + + int AXIS_MINUS_Z +  
        + + int AXIS_X +  
        + + int AXIS_Y +  
        + + int AXIS_Z +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Fields +
        + + int DATA_X +Now deprecated.
        +
         
        + + int DATA_Y +Now deprecated.
        +
         
        + + int DATA_Z +Now deprecated.
        +
         
        + + float LIGHT_NO_MOON +Changed in value from 0.0010f to 0.001f. +  
        + + int RAW_DATA_INDEX +Now deprecated.
        +
         
        + + int RAW_DATA_X +Now deprecated.
        +
         
        + + int RAW_DATA_Y +Now deprecated.
        +
         
        + + int RAW_DATA_Z +Now deprecated.
        +
         
        + + int SENSOR_ACCELEROMETER +Now deprecated.
        +
         
        + + int SENSOR_ALL +Now deprecated.
        +
         
        + + int SENSOR_LIGHT +Now deprecated.
        +
         
        + + int SENSOR_MAGNETIC_FIELD +Now deprecated.
        +
         
        + + int SENSOR_MAX +Now deprecated.
        +
         
        + + int SENSOR_MIN +Now deprecated.
        +
         
        + + int SENSOR_ORIENTATION +Now deprecated.
        +
         
        + + int SENSOR_ORIENTATION_RAW +Now deprecated.
        +
         
        + + int SENSOR_PROXIMITY +Now deprecated.
        +
         
        + + int SENSOR_TEMPERATURE +Now deprecated.
        +
         
        + + int SENSOR_TRICORDER +Now deprecated.
        +
         
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.location.Location.html b/docs/html/sdk/api_diff/3/changes/android.location.Location.html new file mode 100644 index 0000000000000000000000000000000000000000..03d3f894f33c7574ccf1e82e697defb436547493 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.location.Location.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.location.Location + + + + + + + + + + +
        +
        +
        +

        +Class android.location.Location +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void dump(Printer, String) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.location.LocationManager.html b/docs/html/sdk/api_diff/3/changes/android.location.LocationManager.html new file mode 100644 index 0000000000000000000000000000000000000000..4cd68386cbd41974b1ce1261a108c7d52f49fa9e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.location.LocationManager.html @@ -0,0 +1,243 @@ + + + + + + + + + +android.location.LocationManager + + + + + + + + + + +
        +
        +
        +

        +Class android.location.LocationManager +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean addGpsStatusListener(Listener) +  
        + + void addTestProvider(String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int) +  
        + + void clearTestProviderEnabled(String) +  
        + + void clearTestProviderLocation(String) +  
        + + void clearTestProviderStatus(String) +  
        + + GpsStatus getGpsStatus(GpsStatus) +  
        + + void removeGpsStatusListener(Listener) +  
        + + void removeTestProvider(String) +  
        + + void removeUpdates(PendingIntent) +  
        + + void requestLocationUpdates(String, long, float, PendingIntent) +  
        + + boolean sendExtraCommand(String, String, Bundle) +  
        + + void setTestProviderEnabled(String, boolean) +  
        + + void setTestProviderLocation(String, Location) +  
        + + void setTestProviderStatus(String, int, Bundle, long) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String KEY_LOCATION_CHANGED +  
        + + String KEY_PROVIDER_ENABLED +  
        + + String KEY_STATUS_CHANGED +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.media.AudioManager.html b/docs/html/sdk/api_diff/3/changes/android.media.AudioManager.html new file mode 100644 index 0000000000000000000000000000000000000000..a98d840ffaf7f2ba708e10e48256f3f5c3f8d1e1 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.media.AudioManager.html @@ -0,0 +1,227 @@ + + + + + + + + + +android.media.AudioManager + + + + + + + + + + +
        +
        +
        +

        +Class android.media.AudioManager +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean isBluetoothA2dpOn() +  
        + + void playSoundEffect(int, float) +  
        + + void setBluetoothA2dpOn(boolean) +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String ACTION_AUDIO_BECOMING_NOISY +  
        + + int FX_KEYPRESS_DELETE +  
        + + int FX_KEYPRESS_RETURN +  
        + + int FX_KEYPRESS_SPACEBAR +  
        + + int FX_KEYPRESS_STANDARD +  
        + + int ROUTE_BLUETOOTH_A2DP +  
        + + int ROUTE_BLUETOOTH_SCO +  
        + + int STREAM_NOTIFICATION +  
        +  +

        + + + + + + + + + + + + + + +
        Changed Fields +
        + + int NUM_STREAMS +Now deprecated.
        +
         
        + + int ROUTE_BLUETOOTH +Now deprecated.
        +
         
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.media.MediaPlayer.html b/docs/html/sdk/api_diff/3/changes/android.media.MediaPlayer.html new file mode 100644 index 0000000000000000000000000000000000000000..7704e1232ee8e46c592a75f2235aee8b8fc080be --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.media.MediaPlayer.html @@ -0,0 +1,180 @@ + + + + + + + + + +android.media.MediaPlayer + + + + + + + + + + +
        +
        +
        +

        +Class android.media.MediaPlayer +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean isLooping() +  
        + + void setOnInfoListener(OnInfoListener) +  
        + + void setOnVideoSizeChangedListener(OnVideoSizeChangedListener) +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK +  
        + + int MEDIA_INFO_BAD_INTERLEAVING +  
        + + int MEDIA_INFO_NOT_SEEKABLE +  
        + + int MEDIA_INFO_UNKNOWN +  
        + + int MEDIA_INFO_VIDEO_TRACK_LAGGING +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.media.MediaRecorder.OutputFormat.html b/docs/html/sdk/api_diff/3/changes/android.media.MediaRecorder.OutputFormat.html new file mode 100644 index 0000000000000000000000000000000000000000..0967c567c7f4b3e5ffa564ff8463995049a35fee --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.media.MediaRecorder.OutputFormat.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.media.MediaRecorder.OutputFormat + + + + + + + + + + +
        +
        +
        +

        +Class android.media.MediaRecorder.OutputFormat +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + int RAW_AMR +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.media.MediaRecorder.html b/docs/html/sdk/api_diff/3/changes/android.media.MediaRecorder.html new file mode 100644 index 0000000000000000000000000000000000000000..9daf4c350aaa3b23a0edecc7189982084c655539 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.media.MediaRecorder.html @@ -0,0 +1,240 @@ + + + + + + + + + +android.media.MediaRecorder + + + + + + + + + + +
        +
        +
        +

        +Class android.media.MediaRecorder +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void setCamera(Camera) +  
        + + void setMaxDuration(int) +  
        + + void setMaxFileSize(long) +  
        + + void setOnErrorListener(OnErrorListener) +  
        + + void setOnInfoListener(OnInfoListener) +  
        + + void setOutputFile(FileDescriptor) +  
        + + void setVideoEncoder(int) +  
        + + void setVideoFrameRate(int) +  
        + + void setVideoSize(int, int) +  
        + + void setVideoSource(int) +  
        +  +

        + + + + + + + + + +
        Changed Methods +
        + + void prepare() + +Change in exceptions thrown from java.lang.IllegalStateException to (java.io.IOException, java.lang.IllegalStateException).
        +
         
        +  + +

        + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int MEDIA_RECORDER_ERROR_UNKNOWN +  
        + + int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED +  
        + + int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED +  
        + + int MEDIA_RECORDER_INFO_UNKNOWN +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.media.RingtoneManager.html b/docs/html/sdk/api_diff/3/changes/android.media.RingtoneManager.html new file mode 100644 index 0000000000000000000000000000000000000000..e9fdbfc24b04d725358770d49d9e88d8688cc017 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.media.RingtoneManager.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.media.RingtoneManager + + + + + + + + + + +
        +
        +
        +

        +Class android.media.RingtoneManager +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int inferStreamType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.media.SoundPool.html b/docs/html/sdk/api_diff/3/changes/android.media.SoundPool.html new file mode 100644 index 0000000000000000000000000000000000000000..6e765d837f78ca9956fd11e75a234978a9a3cb63 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.media.SoundPool.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.media.SoundPool + + + + + + + + + + +
        +
        +
        +

        +Class android.media.SoundPool +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + int load(AssetFileDescriptor, int) +  
        + + int load(FileDescriptor, long, long, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.net.ConnectivityManager.html b/docs/html/sdk/api_diff/3/changes/android.net.ConnectivityManager.html new file mode 100644 index 0000000000000000000000000000000000000000..7b0750e02f15f2e7586e6a1ea1146755c9d1b614 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.net.ConnectivityManager.html @@ -0,0 +1,138 @@ + + + + + + + + + +android.net.ConnectivityManager + + + + + + + + + + +
        +
        +
        +

        +Class android.net.ConnectivityManager +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean getBackgroundDataSetting() +  
        +  + +

        + + + + + + + + +
        Added Fields +
        + + String ACTION_BACKGROUND_DATA_SETTING_CHANGED +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.net.NetworkInfo.html b/docs/html/sdk/api_diff/3/changes/android.net.NetworkInfo.html new file mode 100644 index 0000000000000000000000000000000000000000..6c3c26d2c4c426af3b0572a49074f0e0154b0bc7 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.net.NetworkInfo.html @@ -0,0 +1,152 @@ + + + + + + + + + +android.net.NetworkInfo + + + + + + + + + + +
        +
        +
        +

        +Class android.net.NetworkInfo +

        + +

        + + + + + + + + +
        Removed Constructors +
        + + NetworkInfo(int) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int getSubtype() +  
        + + String getSubtypeName() +  
        + + boolean isRoaming() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.net.wifi.WifiManager.html b/docs/html/sdk/api_diff/3/changes/android.net.wifi.WifiManager.html new file mode 100644 index 0000000000000000000000000000000000000000..2e79642e7662267920adc75446445afaa1e71c76 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.net.wifi.WifiManager.html @@ -0,0 +1,145 @@ + + + + + + + + + +android.net.wifi.WifiManager + + + + + + + + + + +
        +
        +
        +

        +Class android.net.wifi.WifiManager +

        + + +

        + + + + + + + + +
        Added Methods +
        + + WifiLock createWifiLock(int, String) +  
        +  + +

        + + + + + + + + + + + + +
        Added Fields +
        + + int WIFI_MODE_FULL +  
        + + int WIFI_MODE_SCAN_ONLY +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.Binder.html b/docs/html/sdk/api_diff/3/changes/android.os.Binder.html new file mode 100644 index 0000000000000000000000000000000000000000..882803adaf42ad294af320e3ff1283f5ca926598 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.Binder.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.os.Binder + + + + + + + + + + +
        +
        +
        +

        +Class android.os.Binder +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void dump(FileDescriptor, String[]) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.Build.html b/docs/html/sdk/api_diff/3/changes/android.os.Build.html new file mode 100644 index 0000000000000000000000000000000000000000..2a69a8c7c204c15ac108129dbf11044b30839160 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.Build.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.os.Build + + + + + + + + + + +
        +
        +
        +

        +Class android.os.Build +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + String DISPLAY +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.Debug.html b/docs/html/sdk/api_diff/3/changes/android.os.Debug.html new file mode 100644 index 0000000000000000000000000000000000000000..8e7e2db3eef8db20713fcdc074326490e32eb654 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.Debug.html @@ -0,0 +1,141 @@ + + + + + + + + + +android.os.Debug + + + + + + + + + + +
        +
        +
        +

        +Class android.os.Debug +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void dumpHprofData(String) +  
        +  +

        + + + + + + + + + +
        Changed Methods +
        + + void changeDebugPort(int) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.Environment.html b/docs/html/sdk/api_diff/3/changes/android.os.Environment.html new file mode 100644 index 0000000000000000000000000000000000000000..4cc764375c6416e56d9710b604fd2b9cb14a96ee --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.Environment.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.os.Environment + + + + + + + + + + +
        +
        +
        +

        +Class android.os.Environment +

        + + + +

        + + + + + + + + + + + + +
        Added Fields +
        + + String MEDIA_CHECKING +  
        + + String MEDIA_NOFS +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.Handler.html b/docs/html/sdk/api_diff/3/changes/android.os.Handler.html new file mode 100644 index 0000000000000000000000000000000000000000..fc10c9b29cd1a92d80e0ddf2c63d4451ed9303d3 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.Handler.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.os.Handler + + + + + + + + + + +
        +
        +
        +

        +Class android.os.Handler +

        + +

        + + + + + + + + + + + + +
        Added Constructors +
        + + Handler(Callback) +  
        + + Handler(Looper, Callback) +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.IBinder.html b/docs/html/sdk/api_diff/3/changes/android.os.IBinder.html new file mode 100644 index 0000000000000000000000000000000000000000..95745dc7d4a345719542a0a44e5e4042d8808e4e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.IBinder.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.os.IBinder + + + + + + + + + + +
        +
        +
        +

        +Interface android.os.IBinder +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void dump(FileDescriptor, String[]) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.Looper.html b/docs/html/sdk/api_diff/3/changes/android.os.Looper.html new file mode 100644 index 0000000000000000000000000000000000000000..d79ae756786f49bbb5b1dfe228bf6b7de0342234 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.Looper.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.os.Looper + + + + + + + + + + +
        +
        +
        +

        +Class android.os.Looper +

        + + +

        + + + + + + + + +
        Added Methods +
        + + Thread getThread() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.Parcel.html b/docs/html/sdk/api_diff/3/changes/android.os.Parcel.html new file mode 100644 index 0000000000000000000000000000000000000000..317b722d9f0f350c5e10264e4bfe8ad3627a4f74 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.Parcel.html @@ -0,0 +1,146 @@ + + + + + + + + + +android.os.Parcel + + + + + + + + + + +
        +
        +
        +

        +Class android.os.Parcel +

        + + +

        + + + + + + + + + + + + + + + + + + + +
        Changed Methods +
        + + HashMap readHashMap(ClassLoader) + +Change from deprecated to undeprecated.
        +
         
        + + void readMap(Map, ClassLoader) + +Change from deprecated to undeprecated.
        +
         
        + + void writeMap(Map) + +Change from deprecated to undeprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.os.ParcelFileDescriptor.html b/docs/html/sdk/api_diff/3/changes/android.os.ParcelFileDescriptor.html new file mode 100644 index 0000000000000000000000000000000000000000..77641d54c4dd1ce2ecc745fafaaf65f6851ffb8f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.os.ParcelFileDescriptor.html @@ -0,0 +1,138 @@ + + + + + + + + + +android.os.ParcelFileDescriptor + + + + + + + + + + +
        +
        +
        +

        +Class android.os.ParcelFileDescriptor +

        + + +

        + + + + + + + + +
        Added Methods +
        + + long getStatSize() +  
        +  + +

        + + + + + + + + +
        Added Fields +
        + + int MODE_APPEND +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.preference.DialogPreference.html b/docs/html/sdk/api_diff/3/changes/android.preference.DialogPreference.html new file mode 100644 index 0000000000000000000000000000000000000000..93e05e7c6320ab4fc5e6e9dc6fb5bd7e4bbe866b --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.preference.DialogPreference.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.preference.DialogPreference + + + + + + + + + + +
        +
        +
        +

        +Class android.preference.DialogPreference +

        + + +

        + + + + + + + + +
        Added Methods +
        + + Dialog getDialog() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.Browser.html b/docs/html/sdk/api_diff/3/changes/android.provider.Browser.html new file mode 100644 index 0000000000000000000000000000000000000000..9a9a4b80ef09eba2025eb83792441f1eb74ee16b --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.Browser.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.provider.Browser + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.Browser +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + String EXTRA_APPLICATION_ID +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.Intents.Insert.html b/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.Intents.Insert.html new file mode 100644 index 0000000000000000000000000000000000000000..32541826a88813b4c4dcf3fbfbf654e691b0c2e6 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.Intents.Insert.html @@ -0,0 +1,179 @@ + + + + + + + + + +android.provider.Contacts.Intents.Insert + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.Contacts.Intents.Insert +

        + + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String PHONETIC_NAME +  
        + + String SECONDARY_EMAIL +  
        + + String SECONDARY_EMAIL_TYPE +  
        + + String SECONDARY_PHONE +  
        + + String SECONDARY_PHONE_TYPE +  
        + + String TERTIARY_EMAIL +  
        + + String TERTIARY_EMAIL_TYPE +  
        + + String TERTIARY_PHONE +  
        + + String TERTIARY_PHONE_TYPE +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.Intents.html b/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.Intents.html new file mode 100644 index 0000000000000000000000000000000000000000..1f758333c47ea19692611e0b180e9db40b18ba65 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.Intents.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.provider.Contacts.Intents + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.Contacts.Intents +

        + + + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String EXTRA_CREATE_DESCRIPTION +  
        + + String EXTRA_FORCE_CREATE +  
        + + String SHOW_OR_CREATE_CONTACT +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.PeopleColumns.html b/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.PeopleColumns.html new file mode 100644 index 0000000000000000000000000000000000000000..e8c0f4d6d2c7cb110f9747124663d9ef4f532d2b --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.Contacts.PeopleColumns.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.provider.Contacts.PeopleColumns + + + + + + + + + + +
        +
        +
        +

        +Interface android.provider.Contacts.PeopleColumns +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + String PHONETIC_NAME +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Audio.AlbumColumns.html b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Audio.AlbumColumns.html new file mode 100644 index 0000000000000000000000000000000000000000..ade1498b3082c5371e0be3fed54505523cec30c8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Audio.AlbumColumns.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.provider.MediaStore.Audio.AlbumColumns + + + + + + + + + + +
        +
        +
        +

        +Interface android.provider.MediaStore.Audio.AlbumColumns +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + String NUMBER_OF_SONGS_FOR_ARTIST +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Audio.Media.html b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Audio.Media.html new file mode 100644 index 0000000000000000000000000000000000000000..52bae9d6f275aeb374f27eec3bfb2a76649bbaed --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Audio.Media.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.provider.MediaStore.Audio.Media + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.MediaStore.Audio.Media +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + String EXTRA_MAX_BYTES +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Images.Media.html b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Images.Media.html new file mode 100644 index 0000000000000000000000000000000000000000..b375c3f9959fee75b0ef3f20e612a2beedc9c5fd --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Images.Media.html @@ -0,0 +1,125 @@ + + + + + + + + + +android.provider.MediaStore.Images.Media + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.MediaStore.Images.Media +

        + + + +

        + + + + + + + + + +
        Changed Fields +
        + + String DEFAULT_SORT_ORDER +Changed in value from "name ASC" to "bucket_display_name". +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Video.VideoColumns.html b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Video.VideoColumns.html new file mode 100644 index 0000000000000000000000000000000000000000..43494502563fa1a8d228fa9cac3085cbf3c399c9 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Video.VideoColumns.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.provider.MediaStore.Video.VideoColumns + + + + + + + + + + +
        +
        +
        +

        +Interface android.provider.MediaStore.Video.VideoColumns +

        + + + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String BOOKMARK +  
        + + String BUCKET_DISPLAY_NAME +  
        + + String BUCKET_ID +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Video.html b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Video.html new file mode 100644 index 0000000000000000000000000000000000000000..60437625988c1635d1e9d8d42d3a632b5d5cdd2d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.Video.html @@ -0,0 +1,125 @@ + + + + + + + + + +android.provider.MediaStore.Video + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.MediaStore.Video +

        + + + +

        + + + + + + + + + +
        Changed Fields +
        + + String DEFAULT_SORT_ORDER +Changed in value from "name ASC" to "_display_name". +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.html b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.html new file mode 100644 index 0000000000000000000000000000000000000000..0d6a4cdce690a0d80529e2b429070e1917edb7b1 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.MediaStore.html @@ -0,0 +1,207 @@ + + + + + + + + + +android.provider.MediaStore + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.MediaStore +

        + + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String ACTION_IMAGE_CAPTURE +  
        + + String ACTION_VIDEO_CAPTURE +  
        + + String EXTRA_FINISH_ON_COMPLETION +  
        + + String EXTRA_MEDIA_ALBUM +  
        + + String EXTRA_MEDIA_ARTIST +  
        + + String EXTRA_MEDIA_FOCUS +  
        + + String EXTRA_MEDIA_TITLE +  
        + + String EXTRA_OUTPUT +  
        + + String EXTRA_SCREEN_ORIENTATION +  
        + + String EXTRA_VIDEO_QUALITY +  
        + + String INTENT_ACTION_MEDIA_SEARCH +  
        + + String INTENT_ACTION_STILL_IMAGE_CAMERA +  
        + + String INTENT_ACTION_VIDEO_CAMERA +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.Settings.System.html b/docs/html/sdk/api_diff/3/changes/android.provider.Settings.System.html new file mode 100644 index 0000000000000000000000000000000000000000..b7ef86c6695adf9af772dd0535327b305e58bd17 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.Settings.System.html @@ -0,0 +1,502 @@ + + + + + + + + + +android.provider.Settings.System + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.Settings.System +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + long getLong(ContentResolver, String) +  
        + + long getLong(ContentResolver, String, long) +  
        + + boolean putLong(ContentResolver, String, long) +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String ACCELEROMETER_ROTATION +  
        + + String HAPTIC_FEEDBACK_ENABLED +  
        + + String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED +  
        + + String VOLUME_NOTIFICATION +  
        + + String WIFI_MAX_DHCP_RETRY_COUNT +  
        + + String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS +  
        + + String WIFI_SLEEP_POLICY +  
        + + int WIFI_SLEEP_POLICY_DEFAULT +  
        + + int WIFI_SLEEP_POLICY_NEVER +  
        + + int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Fields +
        + + String ADB_ENABLED +Now deprecated.
        +
         
        + + String ANDROID_ID +Now deprecated.
        +
         
        + + String BLUETOOTH_ON +Now deprecated.
        +
         
        + + String DATA_ROAMING +Now deprecated.
        +
         
        + + String DEVICE_PROVISIONED +Now deprecated.
        +
         
        + + String HTTP_PROXY +Now deprecated.
        +
         
        + + String INSTALL_NON_MARKET_APPS +Now deprecated.
        +
         
        + + String LOCATION_PROVIDERS_ALLOWED +Now deprecated.
        +
         
        + + String LOGGING_ID +Now deprecated.
        +
         
        + + String NETWORK_PREFERENCE +Now deprecated.
        +
         
        + + String PARENTAL_CONTROL_ENABLED +Now deprecated.
        +
         
        + + String PARENTAL_CONTROL_LAST_UPDATE +Now deprecated.
        +
         
        + + String PARENTAL_CONTROL_REDIRECT_URL +Now deprecated.
        +
         
        + + String SETTINGS_CLASSNAME +Now deprecated.
        +
         
        + + String USB_MASS_STORAGE_ENABLED +Now deprecated.
        +
         
        + + String USE_GOOGLE_MAIL +Now deprecated.
        +
         
        + + String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON +Now deprecated.
        +
         
        + + String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY +Now deprecated.
        +
         
        + + String WIFI_NUM_OPEN_NETWORKS_KEPT +Now deprecated.
        +
         
        + + String WIFI_ON +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_AP_COUNT +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_MAX_AP_CHECKS +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_ON +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_PING_COUNT +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_PING_DELAY_MS +Now deprecated.
        +
         
        + + String WIFI_WATCHDOG_PING_TIMEOUT_MS +Now deprecated.
        +
         
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.provider.Settings.html b/docs/html/sdk/api_diff/3/changes/android.provider.Settings.html new file mode 100644 index 0000000000000000000000000000000000000000..227b462ed957f62e02785a95a78da0b3a27a7636 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.provider.Settings.html @@ -0,0 +1,200 @@ + + + + + + + + + +android.provider.Settings + + + + + + + + + + +
        +
        +
        +

        +Class android.provider.Settings +

        + + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String ACTION_AIRPLANE_MODE_SETTINGS +  
        + + String ACTION_APPLICATION_DEVELOPMENT_SETTINGS +  
        + + String ACTION_DATA_ROAMING_SETTINGS +  
        + + String ACTION_INPUT_METHOD_SETTINGS +  
        + + String ACTION_INTERNAL_STORAGE_SETTINGS +  
        + + String ACTION_MANAGE_APPLICATIONS_SETTINGS +  
        + + String ACTION_MEMORY_CARD_SETTINGS +  
        + + String ACTION_NETWORK_OPERATOR_SETTINGS +  
        + + String ACTION_QUICK_LAUNCH_SETTINGS +  
        + + String ACTION_SYNC_SETTINGS +  
        + + String ACTION_USER_DICTIONARY_SETTINGS +  
        + + String ACTION_WIFI_IP_SETTINGS +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.telephony.PhoneNumberUtils.html b/docs/html/sdk/api_diff/3/changes/android.telephony.PhoneNumberUtils.html new file mode 100644 index 0000000000000000000000000000000000000000..6e0b240ca75b23efb2d691b9ccd5749e6a6cd307 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.telephony.PhoneNumberUtils.html @@ -0,0 +1,138 @@ + + + + + + + + + +android.telephony.PhoneNumberUtils + + + + + + + + + + +
        +
        +
        +

        +Class android.telephony.PhoneNumberUtils +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void formatJapaneseNumber(Editable) +  
        +  + +

        + + + + + + + + +
        Added Fields +
        + + int FORMAT_JAPAN +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.telephony.TelephonyManager.html b/docs/html/sdk/api_diff/3/changes/android.telephony.TelephonyManager.html new file mode 100644 index 0000000000000000000000000000000000000000..aa02f5c1f3a858a6ae12d7cb225d4a63d0ade276 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.telephony.TelephonyManager.html @@ -0,0 +1,173 @@ + + + + + + + + + +android.telephony.TelephonyManager + + + + + + + + + + +
        +
        +
        +

        +Class android.telephony.TelephonyManager +

        + + +

        + + + + + + + + +
        Added Methods +
        + + List<NeighboringCellInfo> getNeighboringCellInfo() +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + String ACTION_PHONE_STATE_CHANGED +  
        + + String EXTRA_INCOMING_NUMBER +  
        + + String EXTRA_STATE +  
        + + String EXTRA_STATE_IDLE +  
        + + String EXTRA_STATE_OFFHOOK +  
        + + String EXTRA_STATE_RINGING +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.telephony.gsm.SmsMessage.html b/docs/html/sdk/api_diff/3/changes/android.telephony.gsm.SmsMessage.html new file mode 100644 index 0000000000000000000000000000000000000000..c6069043fe40d52b12ec9bc752db28453ff2a021 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.telephony.gsm.SmsMessage.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.telephony.gsm.SmsMessage + + + + + + + + + + +
        +
        +
        +

        +Class android.telephony.gsm.SmsMessage +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int[] calculateLength(CharSequence, boolean) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.test.ActivityInstrumentationTestCase.html b/docs/html/sdk/api_diff/3/changes/android.test.ActivityInstrumentationTestCase.html new file mode 100644 index 0000000000000000000000000000000000000000..c3360776828e14087f378947d3b980545422ba34 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.test.ActivityInstrumentationTestCase.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.test.ActivityInstrumentationTestCase + + + + + + + + + + +
        +
        +
        +

        +Class android.test.ActivityInstrumentationTestCase +

        +

        Now deprecated.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.test.InstrumentationTestCase.html b/docs/html/sdk/api_diff/3/changes/android.test.InstrumentationTestCase.html new file mode 100644 index 0000000000000000000000000000000000000000..1fb403aaabe59359332cb8fdcfec485b15706501 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.test.InstrumentationTestCase.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.test.InstrumentationTestCase + + + + + + + + + + +
        +
        +
        +

        +Class android.test.InstrumentationTestCase +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + T launchActivityWithIntent(String, Class<T>, Intent) +  
        + + void runTestOnUiThread(Runnable) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.test.ProviderTestCase.html b/docs/html/sdk/api_diff/3/changes/android.test.ProviderTestCase.html new file mode 100644 index 0000000000000000000000000000000000000000..ffbee6091afed74d4f1636581b4cd54b0b4f72fe --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.test.ProviderTestCase.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.test.ProviderTestCase + + + + + + + + + + +
        +
        +
        +

        +Class android.test.ProviderTestCase +

        +

        Now deprecated.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.test.TouchUtils.html b/docs/html/sdk/api_diff/3/changes/android.test.TouchUtils.html new file mode 100644 index 0000000000000000000000000000000000000000..75f9e5e03e2afbbf54c8241c040290c9ee286d35 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.test.TouchUtils.html @@ -0,0 +1,362 @@ + + + + + + + + + +android.test.TouchUtils + + + + + + + + + + +
        +
        +
        +

        +Class android.test.TouchUtils +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void drag(InstrumentationTestCase, float, float, float, float, int) +  
        + + void dragQuarterScreenDown(InstrumentationTestCase, Activity) +  
        + + void dragQuarterScreenUp(InstrumentationTestCase, Activity) +  
        + + int dragViewBy(InstrumentationTestCase, View, int, int, int) +  
        + + int dragViewTo(InstrumentationTestCase, View, int, int, int) +  
        + + void dragViewToBottom(ActivityInstrumentationTestCase, View, int) +  
        + + void dragViewToBottom(InstrumentationTestCase, Activity, View, int) +  
        + + void dragViewToTop(InstrumentationTestCase, View) +  
        + + void dragViewToTop(InstrumentationTestCase, View, int) +  
        + + int dragViewToX(InstrumentationTestCase, View, int, int) +  
        + + int dragViewToY(InstrumentationTestCase, View, int, int) +  
        + + void longClickView(InstrumentationTestCase, View) +  
        + + void scrollToBottom(InstrumentationTestCase, Activity, ViewGroup) +  
        + + void scrollToTop(InstrumentationTestCase, Activity, ViewGroup) +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Methods +
        + + void drag(ActivityInstrumentationTestCase, float, float, float, float, int) + +Now deprecated.
        +
         
        + + void dragQuarterScreenDown(ActivityInstrumentationTestCase) + +Now deprecated.
        +
         
        + + void dragQuarterScreenUp(ActivityInstrumentationTestCase) + +Now deprecated.
        +
         
        + + int dragViewBy(ActivityInstrumentationTestCase, View, int, int, int) + +Now deprecated.
        +
         
        + + int dragViewTo(ActivityInstrumentationTestCase, View, int, int, int) + +Now deprecated.
        +
         
        + + void dragViewToBottom(ActivityInstrumentationTestCase, View) + +Now deprecated.
        +
         
        + + void dragViewToBottom(InstrumentationTestCase, Activity, View) + +Change in signature from (ActivityInstrumentationTestCase, View, int) to (InstrumentationTestCase, Activity, View).
        +
         
        + + void dragViewToTop(ActivityInstrumentationTestCase, View) + +Now deprecated.
        +
         
        + + void dragViewToTop(ActivityInstrumentationTestCase, View, int) + +Now deprecated.
        +
         
        + + int dragViewToX(ActivityInstrumentationTestCase, View, int, int) + +Now deprecated.
        +
         
        + + int dragViewToY(ActivityInstrumentationTestCase, View, int, int) + +Now deprecated.
        +
         
        + + void longClickView(ActivityInstrumentationTestCase, View) + +Now deprecated.
        +
         
        + + void scrollToBottom(ActivityInstrumentationTestCase, ViewGroup) + +Now deprecated.
        +
         
        + + void scrollToTop(ActivityInstrumentationTestCase, ViewGroup) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.test.mock.MockPackageManager.html b/docs/html/sdk/api_diff/3/changes/android.test.mock.MockPackageManager.html new file mode 100644 index 0000000000000000000000000000000000000000..8e727f35f6b83b601ae811f53cad8ea0f760301a --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.test.mock.MockPackageManager.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.test.mock.MockPackageManager + + + + + + + + + + +
        +
        +
        +

        +Class android.test.mock.MockPackageManager +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + Intent getLaunchIntentForPackage(String) +  
        + + String[] getSystemSharedLibraryNames() +  
        + + boolean isSafeMode() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.test.suitebuilder.TestMethod.html b/docs/html/sdk/api_diff/3/changes/android.test.suitebuilder.TestMethod.html new file mode 100644 index 0000000000000000000000000000000000000000..52467f3fbb2fd6b520fbaec366c28ac1daeae73a --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.test.suitebuilder.TestMethod.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.test.suitebuilder.TestMethod + + + + + + + + + + +
        +
        +
        +

        +Class android.test.suitebuilder.TestMethod +

        + +

        + + + + + + + + + + + + +
        Added Constructors +
        + + TestMethod(String, Class<TestCase>) +  
        + + TestMethod(TestCase) +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.test.suitebuilder.TestSuiteBuilder.html b/docs/html/sdk/api_diff/3/changes/android.test.suitebuilder.TestSuiteBuilder.html new file mode 100644 index 0000000000000000000000000000000000000000..548f473b72f56b54b04055279267f41c27df5861 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.test.suitebuilder.TestSuiteBuilder.html @@ -0,0 +1,126 @@ + + + + + + + + + +android.test.suitebuilder.TestSuiteBuilder + + + + + + + + + + +
        +
        +
        +

        +Class android.test.suitebuilder.TestSuiteBuilder +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + TestSuiteBuilder addRequirements(Predicate<TestMethod>) + +Change in signature from void to Predicate<TestMethod>.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.Annotation.html b/docs/html/sdk/api_diff/3/changes/android.text.Annotation.html new file mode 100644 index 0000000000000000000000000000000000000000..863f172ffa65ff5f9b6807dfadd30a86d81da974 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.Annotation.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.Annotation + + + + + + + + + + +
        +
        +
        +

        +Class android.text.Annotation +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + Annotation(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.AutoText.html b/docs/html/sdk/api_diff/3/changes/android.text.AutoText.html new file mode 100644 index 0000000000000000000000000000000000000000..04ef46d33271e7d5626c74150ca7f851690932d5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.AutoText.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.AutoText + + + + + + + + + + +
        +
        +
        +

        +Class android.text.AutoText +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getSize(View) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.SpanWatcher.html b/docs/html/sdk/api_diff/3/changes/android.text.SpanWatcher.html new file mode 100644 index 0000000000000000000000000000000000000000..fd9943a56ff21f0c67db73a237f700ea74e05880 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.SpanWatcher.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.text.SpanWatcher + + + + + + + + + + +
        +
        +
        +

        +Interface android.text.SpanWatcher +

        +

        Added interface android.text.NoCopySpan.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.Spanned.html b/docs/html/sdk/api_diff/3/changes/android.text.Spanned.html new file mode 100644 index 0000000000000000000000000000000000000000..1c861979d67176b6fca94feb2f168aaa2b708be0 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.Spanned.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.text.Spanned + + + + + + + + + + +
        +
        +
        +

        +Interface android.text.Spanned +

        + + + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int SPAN_COMPOSING +  
        + + int SPAN_INTERMEDIATE +  
        + + int SPAN_POINT_MARK_MASK +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.TextUtils.html b/docs/html/sdk/api_diff/3/changes/android.text.TextUtils.html new file mode 100644 index 0000000000000000000000000000000000000000..9fc8dae935ee9a2947f4f156ef5a0a610c504126 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.TextUtils.html @@ -0,0 +1,159 @@ + + + + + + + + + +android.text.TextUtils + + + + + + + + + + +
        +
        +
        +

        +Class android.text.TextUtils +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + void dumpSpans(CharSequence, Printer, String) +  
        + + int getCapsMode(CharSequence, int, int) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int CAP_MODE_CHARACTERS +  
        + + int CAP_MODE_SENTENCES +  
        + + int CAP_MODE_WORDS +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.TextWatcher.html b/docs/html/sdk/api_diff/3/changes/android.text.TextWatcher.html new file mode 100644 index 0000000000000000000000000000000000000000..a3856f851c10205b84f9fe34e34e1dbb8ce121ab --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.TextWatcher.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.text.TextWatcher + + + + + + + + + + +
        +
        +
        +

        +Interface android.text.TextWatcher +

        +

        Added interface android.text.NoCopySpan.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.ArrowKeyMovementMethod.html b/docs/html/sdk/api_diff/3/changes/android.text.method.ArrowKeyMovementMethod.html new file mode 100644 index 0000000000000000000000000000000000000000..6a1ce5eda08086cd61152c47d0952f9eb17b9f20 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.ArrowKeyMovementMethod.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.ArrowKeyMovementMethod + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.ArrowKeyMovementMethod +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean onKeyOther(TextView, Spannable, KeyEvent) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.BaseKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.BaseKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..b8dddc31cea3fb23d124ee844e4b4ad7dce9e085 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.BaseKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.BaseKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.BaseKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean onKeyOther(View, Editable, KeyEvent) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.DateKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.DateKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..d49752c259cfb3f1145ba455ef76a96e8425b529 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.DateKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.DateKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.DateKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.DateTimeKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.DateTimeKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..82734d3833ef5c2980f2dfab66c0544289557cfc --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.DateTimeKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.DateTimeKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.DateTimeKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.DialerKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.DialerKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..435e701ed6891909ea648451127e31828db31d9e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.DialerKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.DialerKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.DialerKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.DigitsKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.DigitsKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..f33d5fe695bd1809050f249571d2567004238eb0 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.DigitsKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.DigitsKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.DigitsKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.KeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.KeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..2b24f03c022d3333e240782d9aff6b802ddb846f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.KeyListener.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.text.method.KeyListener + + + + + + + + + + +
        +
        +
        +

        +Interface android.text.method.KeyListener +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void clearMetaKeyState(View, Editable, int) +  
        + + int getInputType() +  
        + + boolean onKeyOther(View, Editable, KeyEvent) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.MetaKeyKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.MetaKeyKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..ecdedc1edb85be162124965e91c9c9d8801e3337 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.MetaKeyKeyListener.html @@ -0,0 +1,186 @@ + + + + + + + + + +android.text.method.MetaKeyKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.MetaKeyKeyListener +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + long adjustMetaAfterKeypress(long) +  
        + + long clearMetaKeyState(long, int) +  
        + + void clearMetaKeyState(View, Editable, int) +  
        + + void clearMetaKeyState(Editable, int) +  
        + + int getMetaState(long) +  
        + + int getMetaState(long, int) +  
        + + long handleKeyDown(long, int, KeyEvent) +  
        + + long handleKeyUp(long, int, KeyEvent) +  
        + + boolean isSelectingMetaTracker(CharSequence, Object) +  
        + + long resetLockedMeta(long) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.MovementMethod.html b/docs/html/sdk/api_diff/3/changes/android.text.method.MovementMethod.html new file mode 100644 index 0000000000000000000000000000000000000000..a86dff5fea5643d0e8c8d7a421e568eb4f2e753f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.MovementMethod.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.MovementMethod + + + + + + + + + + +
        +
        +
        +

        +Interface android.text.method.MovementMethod +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean onKeyOther(TextView, Spannable, KeyEvent) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.MultiTapKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.MultiTapKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..b7c2f52694ec0354104780b79e3d11b59b84e05d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.MultiTapKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.MultiTapKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.MultiTapKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.QwertyKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.QwertyKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..fff86c659b1300ed598055f62f2a3d8a24cd3d8b --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.QwertyKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.QwertyKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.QwertyKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.ScrollingMovementMethod.html b/docs/html/sdk/api_diff/3/changes/android.text.method.ScrollingMovementMethod.html new file mode 100644 index 0000000000000000000000000000000000000000..acf5dcd844aafbb2b05ebd0a389006ea328e93e2 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.ScrollingMovementMethod.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.ScrollingMovementMethod + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.ScrollingMovementMethod +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean onKeyOther(TextView, Spannable, KeyEvent) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.TextKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.TextKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..f905b3fe75f36f314798984c53291ee7a23921d4 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.TextKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.TextKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.TextKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.TimeKeyListener.html b/docs/html/sdk/api_diff/3/changes/android.text.method.TimeKeyListener.html new file mode 100644 index 0000000000000000000000000000000000000000..0545b2fb42662eb29ed3bbde6918c3639bde29e9 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.TimeKeyListener.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.text.method.TimeKeyListener + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.TimeKeyListener +

        + + +

        + + + + + + + + +
        Added Methods +
        + + int getInputType() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.method.Touch.html b/docs/html/sdk/api_diff/3/changes/android.text.method.Touch.html new file mode 100644 index 0000000000000000000000000000000000000000..fd0f64a6a3c8869395f1d7187b265be65ecc91fd --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.method.Touch.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.text.method.Touch + + + + + + + + + + +
        +
        +
        +

        +Class android.text.method.Touch +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + int getInitialScrollX(TextView, Spannable) +  
        + + int getInitialScrollY(TextView, Spannable) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.AbsoluteSizeSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.AbsoluteSizeSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..32b1098ef891f5e847a697b684b98263998659f1 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.AbsoluteSizeSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.AbsoluteSizeSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.AbsoluteSizeSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + AbsoluteSizeSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.AlignmentSpan.Standard.html b/docs/html/sdk/api_diff/3/changes/android.text.style.AlignmentSpan.Standard.html new file mode 100644 index 0000000000000000000000000000000000000000..86b03d47bbfbee46b6ee6bda25e8aaa2963f73f1 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.AlignmentSpan.Standard.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.AlignmentSpan.Standard + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.AlignmentSpan.Standard +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + AlignmentSpan.Standard(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.BackgroundColorSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.BackgroundColorSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..b7705aaee5f18ec60bca30777e8f09ce8c45aca6 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.BackgroundColorSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.BackgroundColorSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.BackgroundColorSpan +

        +

        Added interfaces android.text.ParcelableSpan, android.text.style.UpdateAppearance.
        + +

        + + + + + + + + +
        Added Constructors +
        + + BackgroundColorSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.BulletSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.BulletSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..10f6d2aa0445a9f0762c9ef193a0a0e2932267eb --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.BulletSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.BulletSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.BulletSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + BulletSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.ClickableSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.ClickableSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..0d7fecb93a4d44641799ee0785076a777c38ee7f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.ClickableSpan.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.text.style.ClickableSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.ClickableSpan +

        +

        Added interface android.text.style.UpdateAppearance.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.DynamicDrawableSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.DynamicDrawableSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..2bc83fa5da736de4145b18f59c6b10cd7eb573f4 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.DynamicDrawableSpan.html @@ -0,0 +1,167 @@ + + + + + + + + + +android.text.style.DynamicDrawableSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.DynamicDrawableSpan +

        + +

        + + + + + + + + +
        Added Constructors +
        + + DynamicDrawableSpan(int) +  
        +  + +

        + + + + + + + + +
        Added Methods +
        + + int getVerticalAlignment() +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int ALIGN_BASELINE +  
        + + int ALIGN_BOTTOM +  
        + + int mVerticalAlignment +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.ForegroundColorSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.ForegroundColorSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..fa483c002d9f04ff0d77c4f84614684b2e483271 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.ForegroundColorSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.ForegroundColorSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.ForegroundColorSpan +

        +

        Added interfaces android.text.ParcelableSpan, android.text.style.UpdateAppearance.
        + +

        + + + + + + + + +
        Added Constructors +
        + + ForegroundColorSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.ImageSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.ImageSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..459e2b7e510c3924c6ab21fb2b9e62674e76c736 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.ImageSpan.html @@ -0,0 +1,151 @@ + + + + + + + + + +android.text.style.ImageSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.ImageSpan +

        + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Constructors +
        + + ImageSpan(Context, Uri, int) +  
        + + ImageSpan(Context, int, int) +  
        + + ImageSpan(Bitmap, int) +  
        + + ImageSpan(Drawable, int) +  
        + + ImageSpan(Drawable, String, int) +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.LeadingMarginSpan.Standard.html b/docs/html/sdk/api_diff/3/changes/android.text.style.LeadingMarginSpan.Standard.html new file mode 100644 index 0000000000000000000000000000000000000000..922bcbc607bc28fcc05994e08ee7735b2c6d1566 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.LeadingMarginSpan.Standard.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.LeadingMarginSpan.Standard + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.LeadingMarginSpan.Standard +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + LeadingMarginSpan.Standard(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.MaskFilterSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.MaskFilterSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..fbd8db93560c21d61ed69a3c484fee009a181076 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.MaskFilterSpan.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.text.style.MaskFilterSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.MaskFilterSpan +

        +

        Added interface android.text.style.UpdateAppearance.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.QuoteSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.QuoteSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..334c2233552a45eafb013ea0e255e8eb65542bfe --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.QuoteSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.QuoteSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.QuoteSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + QuoteSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.RasterizerSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.RasterizerSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..62fb6479f8f72050ea94a86a4f723972dfe6ac3b --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.RasterizerSpan.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.text.style.RasterizerSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.RasterizerSpan +

        +

        Added interface android.text.style.UpdateAppearance.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.RelativeSizeSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.RelativeSizeSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..17d97fba524b120d7fc3b2f36b76c7fb611264dc --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.RelativeSizeSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.RelativeSizeSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.RelativeSizeSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + RelativeSizeSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.ScaleXSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.ScaleXSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..ee289f518ff290fd754ed383531be12e4d69fc26 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.ScaleXSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.ScaleXSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.ScaleXSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + ScaleXSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.StrikethroughSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.StrikethroughSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..f045b964395f95add3b7d51bc78e556aeb8914b4 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.StrikethroughSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.StrikethroughSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.StrikethroughSpan +

        +

        Added interfaces android.text.ParcelableSpan, android.text.style.UpdateAppearance.
        + +

        + + + + + + + + +
        Added Constructors +
        + + StrikethroughSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.StyleSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.StyleSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..fcc16080d017bb71a13ad8489a867be8537c2c5e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.StyleSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.StyleSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.StyleSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + StyleSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.SubscriptSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.SubscriptSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..ec3d56242b156d6c710388ea19eba12a1067da09 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.SubscriptSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.SubscriptSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.SubscriptSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + SubscriptSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.SuperscriptSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.SuperscriptSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..853be697af2423313c1c6f917f8b8b77fc66fe87 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.SuperscriptSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.SuperscriptSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.SuperscriptSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + SuperscriptSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.TextAppearanceSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.TextAppearanceSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..719e68f0ce143cd2e8ed6b225204622f657327ac --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.TextAppearanceSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.TextAppearanceSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.TextAppearanceSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + TextAppearanceSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.TypefaceSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.TypefaceSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..01b74e73408e84b70704b95d0b2b0121429442d8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.TypefaceSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.TypefaceSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.TypefaceSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + TypefaceSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.URLSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.URLSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..2a659a4e35c0c625a74e166f6b526155d3ed741f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.URLSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.URLSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.URLSpan +

        +

        Added interface android.text.ParcelableSpan.
        + +

        + + + + + + + + +
        Added Constructors +
        + + URLSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.UnderlineSpan.html b/docs/html/sdk/api_diff/3/changes/android.text.style.UnderlineSpan.html new file mode 100644 index 0000000000000000000000000000000000000000..6c596a03da917515bf4d96a3e418c76aa50d4828 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.UnderlineSpan.html @@ -0,0 +1,153 @@ + + + + + + + + + +android.text.style.UnderlineSpan + + + + + + + + + + +
        +
        +
        +

        +Class android.text.style.UnderlineSpan +

        +

        Added interfaces android.text.ParcelableSpan, android.text.style.UpdateAppearance.
        + +

        + + + + + + + + +
        Added Constructors +
        + + UnderlineSpan(Parcel) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int describeContents() +  
        + + int getSpanTypeId() +  
        + + void writeToParcel(Parcel, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.text.style.UpdateLayout.html b/docs/html/sdk/api_diff/3/changes/android.text.style.UpdateLayout.html new file mode 100644 index 0000000000000000000000000000000000000000..4cca7b4334760de7af7b124ef413fd9eeb05d466 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.text.style.UpdateLayout.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.text.style.UpdateLayout + + + + + + + + + + +
        +
        +
        +

        +Interface android.text.style.UpdateLayout +

        +

        Added interface android.text.style.UpdateAppearance.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.util.SparseIntArray.html b/docs/html/sdk/api_diff/3/changes/android.util.SparseIntArray.html new file mode 100644 index 0000000000000000000000000000000000000000..5657765133fd71a64e00a25797490bb0149a6e03 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.util.SparseIntArray.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.util.SparseIntArray + + + + + + + + + + +
        +
        +
        +

        +Class android.util.SparseIntArray +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void removeAt(int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.util.TimeUtils.html b/docs/html/sdk/api_diff/3/changes/android.util.TimeUtils.html new file mode 100644 index 0000000000000000000000000000000000000000..3317fae27bb3347cb6aa163c4e86b918b39c31d8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.util.TimeUtils.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.util.TimeUtils + + + + + + + + + + +
        +
        +
        +

        +Class android.util.TimeUtils +

        + + +

        + + + + + + + + +
        Added Methods +
        + + String getTimeZoneDatabaseVersion() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.GestureDetector.SimpleOnGestureListener.html b/docs/html/sdk/api_diff/3/changes/android.view.GestureDetector.SimpleOnGestureListener.html new file mode 100644 index 0000000000000000000000000000000000000000..0e00c6047a5eb0fa751f33a9ed5a3e2e453f7e03 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.GestureDetector.SimpleOnGestureListener.html @@ -0,0 +1,138 @@ + + + + + + + + + +android.view.GestureDetector.SimpleOnGestureListener + + + + + + + + + + +
        +
        +
        +

        +Class android.view.GestureDetector.SimpleOnGestureListener +

        +

        Added interface android.view.GestureDetector.OnDoubleTapListener.
        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean onDoubleTap(MotionEvent) +  
        + + boolean onDoubleTapEvent(MotionEvent) +  
        + + boolean onSingleTapConfirmed(MotionEvent) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.GestureDetector.html b/docs/html/sdk/api_diff/3/changes/android.view.GestureDetector.html new file mode 100644 index 0000000000000000000000000000000000000000..dec5a4d9da9a5f1dc989d325049cff4c2aa3d85d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.GestureDetector.html @@ -0,0 +1,173 @@ + + + + + + + + + +android.view.GestureDetector + + + + + + + + + + +
        +
        +
        +

        +Class android.view.GestureDetector +

        + +

        + + + + + + + + + + + + +
        Added Constructors +
        + + GestureDetector(Context, OnGestureListener) +  
        + + GestureDetector(Context, OnGestureListener, Handler) +  
        +  +

        + + + + + + + + + + + + + + +
        Changed Constructors +
        + + GestureDetector(OnGestureListener) + +Now deprecated.
        +
         
        + + GestureDetector(OnGestureListener, Handler) + +Now deprecated.
        +
         
        +  + +

        + + + + + + + + +
        Added Methods +
        + + void setOnDoubleTapListener(OnDoubleTapListener) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.Gravity.html b/docs/html/sdk/api_diff/3/changes/android.view.Gravity.html new file mode 100644 index 0000000000000000000000000000000000000000..1aa10d3682fbd1c0b10eef66ced242770fe7a3d5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.Gravity.html @@ -0,0 +1,166 @@ + + + + + + + + + +android.view.Gravity + + + + + + + + + + +
        +
        +
        +

        +Class android.view.Gravity +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void applyDisplay(int, Rect, Rect) +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int AXIS_CLIP +  
        + + int CLIP_HORIZONTAL +  
        + + int CLIP_VERTICAL +  
        + + int DISPLAY_CLIP_HORIZONTAL +  
        + + int DISPLAY_CLIP_VERTICAL +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.KeyCharacterMap.html b/docs/html/sdk/api_diff/3/changes/android.view.KeyCharacterMap.html new file mode 100644 index 0000000000000000000000000000000000000000..7a409cbe130886f5c8868d21e27bb4d7fef0d63f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.KeyCharacterMap.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.view.KeyCharacterMap + + + + + + + + + + +
        +
        +
        +

        +Class android.view.KeyCharacterMap +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + boolean deviceHasKey(int) +  
        + + boolean[] deviceHasKeys(int[]) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.KeyEvent.html b/docs/html/sdk/api_diff/3/changes/android.view.KeyEvent.html new file mode 100644 index 0000000000000000000000000000000000000000..bf3ec6b22e018ef25ed8f8389b73dfae0e0b40dd --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.KeyEvent.html @@ -0,0 +1,275 @@ + + + + + + + + + +android.view.KeyEvent + + + + + + + + + + +
        +
        +
        +

        +Class android.view.KeyEvent +

        + +

        + + + + + + + + + + + + +
        Added Constructors +
        + + KeyEvent(KeyEvent) +  
        + + KeyEvent(long, String, int, int) +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + KeyEvent changeAction(KeyEvent, int) +  
        + + KeyEvent changeFlags(KeyEvent, int) +  
        + + KeyEvent changeTimeRepeat(KeyEvent, long, int) +  
        + + String getCharacters() +  
        + + int getMaxKeyCode() +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int FLAG_EDITOR_ACTION +  
        + + int FLAG_FROM_SYSTEM +  
        + + int FLAG_KEEP_TOUCH_MODE +  
        + + int FLAG_SOFT_KEYBOARD +  
        + + int KEYCODE_MEDIA_FAST_FORWARD +  
        + + int KEYCODE_MEDIA_NEXT +  
        + + int KEYCODE_MEDIA_PLAY_PAUSE +  
        + + int KEYCODE_MEDIA_PREVIOUS +  
        + + int KEYCODE_MEDIA_REWIND +  
        + + int KEYCODE_MEDIA_STOP +  
        + + int KEYCODE_MUTE +  
        +  +

        + + + + + + + + + +
        Changed Fields +
        + + int MAX_KEYCODE +Now deprecated.
        +
         
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.Menu.html b/docs/html/sdk/api_diff/3/changes/android.view.Menu.html new file mode 100644 index 0000000000000000000000000000000000000000..09b910a426888a3981302ae3d4ad01dfbc24081d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.Menu.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.view.Menu + + + + + + + + + + +
        +
        +
        +

        +Interface android.view.Menu +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + void close() +  
        + + MenuItem getItem(int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.MotionEvent.html b/docs/html/sdk/api_diff/3/changes/android.view.MotionEvent.html new file mode 100644 index 0000000000000000000000000000000000000000..5291df778213573655faddc6894cd8450d2f2477 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.MotionEvent.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.view.MotionEvent + + + + + + + + + + +
        +
        +
        +

        +Class android.view.MotionEvent +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + int ACTION_OUTSIDE +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.OrientationListener.html b/docs/html/sdk/api_diff/3/changes/android.view.OrientationListener.html new file mode 100644 index 0000000000000000000000000000000000000000..ac58489da46a311c5d2e1e3b81ff54b7262c7bf6 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.OrientationListener.html @@ -0,0 +1,124 @@ + + + + + + + + + +android.view.OrientationListener + + + + + + + + + + +
        +
        +
        +

        +Class android.view.OrientationListener +

        +

        Now deprecated.
        + +

        + + + + + + + + +
        Added Constructors +
        + + OrientationListener(Context, int) +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.View.html b/docs/html/sdk/api_diff/3/changes/android.view.View.html new file mode 100644 index 0000000000000000000000000000000000000000..ccd58a9d2c8a77736d0694216ca67a0c8d236677 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.View.html @@ -0,0 +1,257 @@ + + + + + + + + + +android.view.View + + + + + + + + + + +
        +
        +
        +

        +Class android.view.View +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean checkInputConnectionProxy(View) +  
        + + boolean dispatchKeyEventPreIme(KeyEvent) +  
        + + void getWindowVisibleDisplayFrame(Rect) +  
        + + boolean isHapticFeedbackEnabled() +  
        + + boolean isInEditMode() +  
        + + boolean onCheckIsTextEditor() +  
        + + InputConnection onCreateInputConnection(EditorInfo) +  
        + + void onFinishTemporaryDetach() +  
        + + boolean onKeyPreIme(int, KeyEvent) +  
        + + void onStartTemporaryDetach() +  
        + + boolean performHapticFeedback(int) +  
        + + boolean performHapticFeedback(int, int) +  
        + + void setHapticFeedbackEnabled(boolean) +  
        + + void setScrollContainer(boolean) +  
        +  +

        + + + + + + + + + + + + + + +
        Changed Methods +
        + + Handler getHandler() + +Change of visibility from protected to public.
        +
         
        + + void playSoundEffect(int) + +Change of visibility from protected to public.
        +
         
        +  + +

        + + + + + + + + +
        Added Fields +
        + + int HAPTIC_FEEDBACK_ENABLED +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.ViewConfiguration.html b/docs/html/sdk/api_diff/3/changes/android.view.ViewConfiguration.html new file mode 100644 index 0000000000000000000000000000000000000000..0bf487c289d7889c8c1b66e7a19fe3924fc0e8d9 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.ViewConfiguration.html @@ -0,0 +1,282 @@ + + + + + + + + + +android.view.ViewConfiguration + + + + + + + + + + +
        +
        +
        +

        +Class android.view.ViewConfiguration +

        + +

        + + + + + + + + + +
        Changed Constructors +
        + + ViewConfiguration() + +Now deprecated.
        +
         
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + ViewConfiguration get(Context) +  
        + + int getDoubleTapTimeout() +  
        + + int getScaledDoubleTapSlop() +  
        + + int getScaledEdgeSlop() +  
        + + int getScaledFadingEdgeLength() +  
        + + int getScaledMaximumDrawingCacheSize() +  
        + + int getScaledMinimumFlingVelocity() +  
        + + int getScaledScrollBarSize() +  
        + + int getScaledTouchSlop() +  
        + + int getScaledWindowTouchSlop() +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Methods +
        + + int getEdgeSlop() + +Now deprecated.
        +
         
        + + int getFadingEdgeLength() + +Now deprecated.
        +
         
        + + int getMaximumDrawingCacheSize() + +Now deprecated.
        +
         
        + + int getMinimumFlingVelocity() + +Now deprecated.
        +
         
        + + int getScrollBarSize() + +Now deprecated.
        +
         
        + + int getTouchSlop() + +Now deprecated.
        +
         
        + + int getWindowTouchSlop() + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.ViewDebug.html b/docs/html/sdk/api_diff/3/changes/android.view.ViewDebug.html new file mode 100644 index 0000000000000000000000000000000000000000..17c0c8a34ebe3a3e04bb939339f17c0529f6fd3d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.ViewDebug.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.view.ViewDebug + + + + + + + + + + +
        +
        +
        +

        +Class android.view.ViewDebug +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void dumpCapturedView(String, Object) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.ViewGroup.html b/docs/html/sdk/api_diff/3/changes/android.view.ViewGroup.html new file mode 100644 index 0000000000000000000000000000000000000000..589f266ff2cfa1fb9c37df237a3e935bd45ec9ac --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.ViewGroup.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.view.ViewGroup + + + + + + + + + + +
        +
        +
        +

        +Class android.view.ViewGroup +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void setStaticTransformationsEnabled(boolean) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.ViewParent.html b/docs/html/sdk/api_diff/3/changes/android.view.ViewParent.html new file mode 100644 index 0000000000000000000000000000000000000000..536e7e95c4fd13d860d6dd5652245310c136023a --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.ViewParent.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.view.ViewParent + + + + + + + + + + +
        +
        +
        +

        +Interface android.view.ViewParent +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean requestChildRectangleOnScreen(View, Rect, boolean) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.ViewTreeObserver.html b/docs/html/sdk/api_diff/3/changes/android.view.ViewTreeObserver.html new file mode 100644 index 0000000000000000000000000000000000000000..41753a737d448c65bb25467f0135045707b934df --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.ViewTreeObserver.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.view.ViewTreeObserver + + + + + + + + + + +
        +
        +
        +

        +Class android.view.ViewTreeObserver +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + void addOnScrollChangedListener(OnScrollChangedListener) +  
        + + void removeOnScrollChangedListener(OnScrollChangedListener) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.Window.html b/docs/html/sdk/api_diff/3/changes/android.view.Window.html new file mode 100644 index 0000000000000000000000000000000000000000..d84eb2b11810b824fec12633bb913b1b3e6818ca --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.Window.html @@ -0,0 +1,137 @@ + + + + + + + + + +android.view.Window + + + + + + + + + + +
        +
        +
        +

        +Class android.view.Window +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean hasSoftInputMode() +  
        + + void setSoftInputMode(int) +  
        + + void setWindowAnimations(int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.WindowManager.LayoutParams.html b/docs/html/sdk/api_diff/3/changes/android.view.WindowManager.LayoutParams.html new file mode 100644 index 0000000000000000000000000000000000000000..7304b0ea78767593b2b94f53696087d8dc08dc23 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.WindowManager.LayoutParams.html @@ -0,0 +1,292 @@ + + + + + + + + + +android.view.WindowManager.LayoutParams + + + + + + + + + + +
        +
        +
        +

        +Class android.view.WindowManager.LayoutParams +

        + + +

        + + + + + + + + +
        Added Methods +
        + + boolean mayUseInputMethod(int) +  
        +  + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int FLAG_ALT_FOCUSABLE_IM +  
        + + int FLAG_WATCH_OUTSIDE_TOUCH +  
        + + int SCREEN_BRIGHTNESS_CHANGED +  
        + + int SCREEN_ORIENTATION_CHANGED +  
        + + int SOFT_INPUT_ADJUST_PAN +  
        + + int SOFT_INPUT_ADJUST_RESIZE +  
        + + int SOFT_INPUT_ADJUST_UNSPECIFIED +  
        + + int SOFT_INPUT_IS_FORWARD_NAVIGATION +  
        + + int SOFT_INPUT_MASK_ADJUST +  
        + + int SOFT_INPUT_MASK_STATE +  
        + + int SOFT_INPUT_MODE_CHANGED +  
        + + int SOFT_INPUT_STATE_ALWAYS_HIDDEN +  
        + + int SOFT_INPUT_STATE_ALWAYS_VISIBLE +  
        + + int SOFT_INPUT_STATE_HIDDEN +  
        + + int SOFT_INPUT_STATE_UNCHANGED +  
        + + int SOFT_INPUT_STATE_UNSPECIFIED +  
        + + int SOFT_INPUT_STATE_VISIBLE +  
        + + int TYPE_APPLICATION_ATTACHED_DIALOG +  
        + + int TYPE_INPUT_METHOD +  
        + + int TYPE_INPUT_METHOD_DIALOG +  
        + + float screenBrightness +  
        + + int screenOrientation +  
        + + int softInputMode +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.animation.Animation.html b/docs/html/sdk/api_diff/3/changes/android.view.animation.Animation.html new file mode 100644 index 0000000000000000000000000000000000000000..9cdf434cb74e163554823c83a781057d61dd8e01 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.animation.Animation.html @@ -0,0 +1,138 @@ + + + + + + + + + +android.view.animation.Animation + + + + + + + + + + +
        +
        +
        +

        +Class android.view.animation.Animation +

        +

        Added interface java.lang.Cloneable.
        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + long computeDurationHint() +  
        + + boolean isFillEnabled() +  
        + + void setFillEnabled(boolean) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.view.animation.Transformation.html b/docs/html/sdk/api_diff/3/changes/android.view.animation.Transformation.html new file mode 100644 index 0000000000000000000000000000000000000000..8c5cbf55cf32b8ff1d597612920f3e45ef17b625 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.view.animation.Transformation.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.view.animation.Transformation + + + + + + + + + + +
        +
        +
        +

        +Class android.view.animation.Transformation +

        + + +

        + + + + + + + + +
        Added Methods +
        + + String toShortString() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.webkit.URLUtil.html b/docs/html/sdk/api_diff/3/changes/android.webkit.URLUtil.html new file mode 100644 index 0000000000000000000000000000000000000000..cff874168f2d4d1d330a2bc20d5006b3f5a5eeb3 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.webkit.URLUtil.html @@ -0,0 +1,126 @@ + + + + + + + + + +android.webkit.URLUtil + + + + + + + + + + +
        +
        +
        +

        +Class android.webkit.URLUtil +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + boolean isCookielessProxyUrl(String) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.webkit.UrlInterceptHandler.html b/docs/html/sdk/api_diff/3/changes/android.webkit.UrlInterceptHandler.html new file mode 100644 index 0000000000000000000000000000000000000000..8664bc6e18f7a643952ad1c0fa03e561361cb4ef --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.webkit.UrlInterceptHandler.html @@ -0,0 +1,141 @@ + + + + + + + + + +android.webkit.UrlInterceptHandler + + + + + + + + + + +
        +
        +
        +

        +Interface android.webkit.UrlInterceptHandler +

        + + +

        + + + + + + + + +
        Added Methods +
        + + PluginData getPluginData(String, Map<String, String>) +  
        +  +

        + + + + + + + + + +
        Changed Methods +
        + + CacheResult service(String, Map<String, String>) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.webkit.UrlInterceptRegistry.html b/docs/html/sdk/api_diff/3/changes/android.webkit.UrlInterceptRegistry.html new file mode 100644 index 0000000000000000000000000000000000000000..09d11496ddf4abfaa93083107ad83c19d5f86695 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.webkit.UrlInterceptRegistry.html @@ -0,0 +1,141 @@ + + + + + + + + + +android.webkit.UrlInterceptRegistry + + + + + + + + + + +
        +
        +
        +

        +Class android.webkit.UrlInterceptRegistry +

        + + +

        + + + + + + + + +
        Added Methods +
        + + PluginData getPluginData(String, Map<String, String>) +  
        +  +

        + + + + + + + + + +
        Changed Methods +
        + + CacheResult getSurrogate(String, Map<String, String>) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.webkit.WebHistoryItem.html b/docs/html/sdk/api_diff/3/changes/android.webkit.WebHistoryItem.html new file mode 100644 index 0000000000000000000000000000000000000000..10140196bb07441a3ca8a4933e7163187378ec55 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.webkit.WebHistoryItem.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.webkit.WebHistoryItem + + + + + + + + + + +
        +
        +
        +

        +Class android.webkit.WebHistoryItem +

        + + +

        + + + + + + + + +
        Added Methods +
        + + String getOriginalUrl() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.webkit.WebSettings.html b/docs/html/sdk/api_diff/3/changes/android.webkit.WebSettings.html new file mode 100644 index 0000000000000000000000000000000000000000..eb421cf63ad7bbdf575ce7bbbe442cecdf399d9f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.webkit.WebSettings.html @@ -0,0 +1,186 @@ + + + + + + + + + +android.webkit.WebSettings + + + + + + + + + + +
        +
        +
        +

        +Class android.webkit.WebSettings +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + boolean getAllowFileAccess() +  
        + + boolean getBuiltInZoomControls() +  
        + + String getUserAgentString() +  
        + + void setAllowFileAccess(boolean) +  
        + + void setBuiltInZoomControls(boolean) +  
        + + void setUserAgentString(String) +  
        +  +

        + + + + + + + + + + + + + + +
        Changed Methods +
        + + int getUserAgent() + +Now deprecated.
        +
         
        + + void setUserAgent(int) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.webkit.WebView.html b/docs/html/sdk/api_diff/3/changes/android.webkit.WebView.html new file mode 100644 index 0000000000000000000000000000000000000000..cd721c8fdfffd7fc2fdcbafdd7a9dccbda04ffc7 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.webkit.WebView.html @@ -0,0 +1,193 @@ + + + + + + + + + +android.webkit.WebView + + + + + + + + + + +
        +
        +
        +

        +Class android.webkit.WebView +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void clearMatches() +  
        + + int findAll(String) +  
        + + void findNext(boolean) +  
        + + String getOriginalUrl() +  
        + + boolean restorePicture(Bundle, File) +  
        + + boolean savePicture(Bundle, File) +  
        + + void setNetworkAvailable(boolean) +  
        +  +

        + + + + + + + + + + + + + + +
        Changed Methods +
        + + View getZoomControls() + +Now deprecated.
        +
         
        + + void onGlobalFocusChanged(View, View) + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.AbsListView.html b/docs/html/sdk/api_diff/3/changes/android.widget.AbsListView.html new file mode 100644 index 0000000000000000000000000000000000000000..6d1ed3535a440092c9c726ffed3ff24fc3c18b81 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.AbsListView.html @@ -0,0 +1,151 @@ + + + + + + + + + +android.widget.AbsListView + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.AbsListView +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + CharSequence getTextFilter() +  
        + + boolean isFastScrollEnabled() +  
        + + boolean isSmoothScrollbarEnabled() +  
        + + void setFastScrollEnabled(boolean) +  
        + + void setSmoothScrollbarEnabled(boolean) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.AbsSeekBar.html b/docs/html/sdk/api_diff/3/changes/android.widget.AbsSeekBar.html new file mode 100644 index 0000000000000000000000000000000000000000..128b31f182e9aebbfb7337ed69d4e63cf3229c76 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.AbsSeekBar.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.widget.AbsSeekBar + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.AbsSeekBar +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + int getKeyProgressIncrement() +  
        + + void setKeyProgressIncrement(int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.AbsoluteLayout.html b/docs/html/sdk/api_diff/3/changes/android.widget.AbsoluteLayout.html new file mode 100644 index 0000000000000000000000000000000000000000..77025f08c08e519b5b2b1e5f4b7e3df764f49b71 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.AbsoluteLayout.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.widget.AbsoluteLayout + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.AbsoluteLayout +

        +

        Now deprecated.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.ArrayAdapter.html b/docs/html/sdk/api_diff/3/changes/android.widget.ArrayAdapter.html new file mode 100644 index 0000000000000000000000000000000000000000..0beed263f3fbb1729474ca2da1ed5cd71e2aeb28 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.ArrayAdapter.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.widget.ArrayAdapter + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.ArrayAdapter +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void sort(Comparator<? super T>) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.AutoCompleteTextView.html b/docs/html/sdk/api_diff/3/changes/android.widget.AutoCompleteTextView.html new file mode 100644 index 0000000000000000000000000000000000000000..a6e89e41b5641dc21c91a63233d33edd34ed0426 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.AutoCompleteTextView.html @@ -0,0 +1,214 @@ + + + + + + + + + +android.widget.AutoCompleteTextView + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.AutoCompleteTextView +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void clearListSelection() +  
        + + int getDropDownAnchor() +  
        + + int getDropDownWidth() +  
        + + int getListSelection() +  
        + + OnItemClickListener getOnItemClickListener() +  
        + + OnItemSelectedListener getOnItemSelectedListener() +  
        + + boolean isPerformingCompletion() +  
        + + void setDropDownAnchor(int) +  
        + + void setDropDownWidth(int) +  
        + + void setListSelection(int) +  
        +  +

        + + + + + + + + + + + + + + +
        Changed Methods +
        + + OnItemClickListener getItemClickListener() + +Now deprecated.
        +
         
        + + OnItemSelectedListener getItemSelectedListener() + +Now deprecated.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.Chronometer.html b/docs/html/sdk/api_diff/3/changes/android.widget.Chronometer.html new file mode 100644 index 0000000000000000000000000000000000000000..2a82a201933a78bf372a5435b22657c2bf66ff37 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.Chronometer.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.widget.Chronometer + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.Chronometer +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + OnChronometerTickListener getOnChronometerTickListener() +  
        + + void setOnChronometerTickListener(OnChronometerTickListener) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.CursorAdapter.html b/docs/html/sdk/api_diff/3/changes/android.widget.CursorAdapter.html new file mode 100644 index 0000000000000000000000000000000000000000..0a890300efd132670c2e755bc05cdcc96bb07adc --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.CursorAdapter.html @@ -0,0 +1,161 @@ + + + + + + + + + +android.widget.CursorAdapter + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.CursorAdapter +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void onContentChanged() +  
        +  +

        + + + + + + + + + + + + + + + + + + + +
        Changed Methods +
        + + int getCount() + +Change from final to non-final.
        +
         
        + + Object getItem(int) + +Change from final to non-final.
        +
         
        + + long getItemId(int) + +Change from final to non-final.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.GridView.html b/docs/html/sdk/api_diff/3/changes/android.widget.GridView.html new file mode 100644 index 0000000000000000000000000000000000000000..86e019ba9ce0ba55b4ebf0512939c256eb506e39 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.GridView.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.widget.GridView + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.GridView +

        + + + +

        + + + + + + + + +
        Added Fields +
        + + int STRETCH_SPACING_UNIFORM +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.ListView.html b/docs/html/sdk/api_diff/3/changes/android.widget.ListView.html new file mode 100644 index 0000000000000000000000000000000000000000..ecaf3096e5989f6a8a008fbf8a00e269e57e1746 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.ListView.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.widget.ListView + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.ListView +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + void setFooterDividersEnabled(boolean) +  
        + + void setHeaderDividersEnabled(boolean) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.PopupWindow.OnDismissListener.html b/docs/html/sdk/api_diff/3/changes/android.widget.PopupWindow.OnDismissListener.html new file mode 100644 index 0000000000000000000000000000000000000000..2e08886708b916f6d011496d42481afa25f42650 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.PopupWindow.OnDismissListener.html @@ -0,0 +1,109 @@ + + + + + + + + + +android.widget.PopupWindow.OnDismissListener + + + + + + + + + + +
        +
        +
        +

        +Interface android.widget.PopupWindow.OnDismissListener +

        +

        Change of visibility from to public.
        + + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.PopupWindow.html b/docs/html/sdk/api_diff/3/changes/android.widget.PopupWindow.html new file mode 100644 index 0000000000000000000000000000000000000000..b3a33037a77ef87cbf9c2f06cb43be6d4f1df7fe --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.PopupWindow.html @@ -0,0 +1,243 @@ + + + + + + + + + +android.widget.PopupWindow + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.PopupWindow +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + int getInputMethodMode() +  
        + + int getMaxAvailableHeight(View, int) +  
        + + boolean isAboveAnchor() +  
        + + boolean isClippingEnabled() +  
        + + boolean isOutsideTouchable() +  
        + + boolean isTouchable() +  
        + + void setClippingEnabled(boolean) +  
        + + void setInputMethodMode(int) +  
        + + void setOutsideTouchable(boolean) +  
        + + void setTouchInterceptor(OnTouchListener) +  
        + + void setTouchable(boolean) +  
        + + void setWindowLayoutMode(int, int) +  
        + + void update() +  
        + + void update(int, int, int, int, boolean) +  
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int INPUT_METHOD_FROM_FOCUSABLE +  
        + + int INPUT_METHOD_NEEDED +  
        + + int INPUT_METHOD_NOT_NEEDED +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.ProgressBar.html b/docs/html/sdk/api_diff/3/changes/android.widget.ProgressBar.html new file mode 100644 index 0000000000000000000000000000000000000000..eea94f2b5e04125753c4a9563b67b791d2b1765e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.ProgressBar.html @@ -0,0 +1,136 @@ + + + + + + + + + +android.widget.ProgressBar + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.ProgressBar +

        + + +

        + + + + + + + + + + + + + + +
        Changed Methods +
        + + void onRestoreInstanceState(Parcelable) + +Method was inherited from android.view.View, but is now defined locally. Change of visibility from protected to public.
        +
         
        + + Parcelable onSaveInstanceState() + +Method was inherited from android.view.View, but is now defined locally. Change of visibility from protected to public.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.RemoteViews.ActionException.html b/docs/html/sdk/api_diff/3/changes/android.widget.RemoteViews.ActionException.html new file mode 100644 index 0000000000000000000000000000000000000000..c2f5c9623291f4c22d004562aa6f7cc3479b1c21 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.RemoteViews.ActionException.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.widget.RemoteViews.ActionException + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.RemoteViews.ActionException +

        + +

        + + + + + + + + +
        Added Constructors +
        + + RemoteViews.ActionException(Exception) +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.RemoteViews.html b/docs/html/sdk/api_diff/3/changes/android.widget.RemoteViews.html new file mode 100644 index 0000000000000000000000000000000000000000..ef8eb08260802e3c7bbd56585ad9c231e593fa65 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.RemoteViews.html @@ -0,0 +1,221 @@ + + + + + + + + + +android.widget.RemoteViews + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.RemoteViews +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void setBitmap(int, String, Bitmap) +  
        + + void setBoolean(int, String, boolean) +  
        + + void setByte(int, String, byte) +  
        + + void setChar(int, String, char) +  
        + + void setCharSequence(int, String, CharSequence) +  
        + + void setDouble(int, String, double) +  
        + + void setFloat(int, String, float) +  
        + + void setImageViewBitmap(int, Bitmap) +  
        + + void setInt(int, String, int) +  
        + + void setLong(int, String, long) +  
        + + void setOnClickPendingIntent(int, PendingIntent) +  
        + + void setShort(int, String, short) +  
        + + void setString(int, String, String) +  
        + + void setTextColor(int, int) +  
        + + void setUri(int, String, Uri) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.ResourceCursorAdapter.html b/docs/html/sdk/api_diff/3/changes/android.widget.ResourceCursorAdapter.html new file mode 100644 index 0000000000000000000000000000000000000000..cee8f59b3d293311209f05d8b6a2efd4e0b7e112 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.ResourceCursorAdapter.html @@ -0,0 +1,138 @@ + + + + + + + + + +android.widget.ResourceCursorAdapter + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.ResourceCursorAdapter +

        + +

        + + + + + + + + +
        Added Constructors +
        + + ResourceCursorAdapter(Context, int, Cursor, boolean) +  
        +  + +

        + + + + + + + + +
        Added Methods +
        + + void setViewResource(int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.Scroller.html b/docs/html/sdk/api_diff/3/changes/android.widget.Scroller.html new file mode 100644 index 0000000000000000000000000000000000000000..e5b524df665889f49af775bc73de8ebdc605acd3 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.Scroller.html @@ -0,0 +1,130 @@ + + + + + + + + + +android.widget.Scroller + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.Scroller +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + int getStartX() +  
        + + int getStartY() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.SimpleCursorAdapter.html b/docs/html/sdk/api_diff/3/changes/android.widget.SimpleCursorAdapter.html new file mode 100644 index 0000000000000000000000000000000000000000..63b7b132902cac541174819f15f0a5da91b00909 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.SimpleCursorAdapter.html @@ -0,0 +1,123 @@ + + + + + + + + + +android.widget.SimpleCursorAdapter + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.SimpleCursorAdapter +

        + + +

        + + + + + + + + +
        Added Methods +
        + + void changeCursorAndColumns(Cursor, String[], int[]) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/android.widget.TextView.html b/docs/html/sdk/api_diff/3/changes/android.widget.TextView.html new file mode 100644 index 0000000000000000000000000000000000000000..42ecdc9f58fa3ae86c4ba4c5edb40f829852bdf5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/android.widget.TextView.html @@ -0,0 +1,333 @@ + + + + + + + + + +android.widget.TextView + + + + + + + + + + +
        +
        +
        +

        +Class android.widget.TextView +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void beginBatchEdit() +  
        + + boolean bringPointIntoView(int) +  
        + + void clearComposingText() +  
        + + boolean didTouchFocusSelect() +  
        + + void endBatchEdit() +  
        + + boolean extractText(ExtractedTextRequest, ExtractedText) +  
        + + Editable getEditableText() +  
        + + int getImeActionId() +  
        + + CharSequence getImeActionLabel() +  
        + + int getImeOptions() +  
        + + Bundle getInputExtras(boolean) +  
        + + int getInputType() +  
        + + String getPrivateImeOptions() +  
        + + boolean isInputMethodTarget() +  
        + + boolean moveCursorToVisibleOffset() +  
        + + void onBeginBatchEdit() +  
        + + void onCommitCompletion(CompletionInfo) +  
        + + void onEditorAction(int) +  
        + + void onEndBatchEdit() +  
        + + boolean onPrivateIMECommand(String, Bundle) +  
        + + void onSelectionChanged(int, int) +  
        + + boolean onTextContextMenuItem(int) +  
        + + void setCompoundDrawablesWithIntrinsicBounds(int, int, int, int) +  
        + + void setExtractedText(ExtractedText) +  
        + + void setImeActionLabel(CharSequence, int) +  
        + + void setImeOptions(int) +  
        + + void setInputExtras(int) +  
        + + void setInputType(int) +  
        + + void setOnEditorActionListener(OnEditorActionListener) +  
        + + void setPrivateImeOptions(String) +  
        + + void setRawInputType(int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/changes-summary.html b/docs/html/sdk/api_diff/3/changes/changes-summary.html new file mode 100644 index 0000000000000000000000000000000000000000..bf52a96580769a8388c08eda333c466c3a7c9a31 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/changes-summary.html @@ -0,0 +1,451 @@ + + + + + + + + + +Android API Differences Report + + + + + + + + + + +
        +
        +
        +
        +

        Android API Differences Report

        +

        This report details the changes in the core Android framework API between two API Level +specifications. It shows additions, modifications, and removals for packages, classes, methods, and fields. +The report also includes general statistics that characterize the extent and type of the differences.

        +

        This report is based a comparison of the Android API specifications +whose API Level identifiers are given in the upper-right corner of this page. It compares a +newer "to" API to an older "from" API, noting all changes relative to the +older API. So, for example, API elements marked as removed are no longer present in the "to" +API specification.

        +

        To navigate the report, use the "Select a Diffs Index" and "Filter the Index" +controls on the left. The report uses text formatting to indicate interface names, +links to reference documentation, and links to change +description. The statistics are accessible from the "Statistics" link in the upper-right corner.

        +

        For more information about the Android framework API and SDK, +see the Android Developers site.

        +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Packages +
        + + android.appwidget +  
        + + android.inputmethodservice +  
        + + android.speech +  
        + + android.text.format +  
        + + android.view.inputmethod +  
        + + java.beans +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Packages +
        + + android +  
        + + android.app +  
        + + android.content +  
        + + android.content.pm +  
        + + android.content.res +  
        + + android.database +  
        + + android.database.sqlite +  
        + + android.graphics +  
        + + android.graphics.drawable +  
        + + android.graphics.drawable.shapes +  
        + + android.hardware +  
        + + android.location +  
        + + android.media +  
        + + android.net +  
        + + android.net.wifi +  
        + + android.opengl +  
        + + android.os +  
        + + android.preference +  
        + + android.provider +  
        + + android.telephony +  
        + + android.telephony.gsm +  
        + + android.test +  
        + + android.test.mock +  
        + + android.test.suitebuilder +  
        + + android.text +  
        + + android.text.method +  
        + + android.text.style +  
        + + android.util +  
        + + android.view +  
        + + android.view.animation +  
        + + android.webkit +  
        + + android.widget +  
        + + dalvik.system +  
        + + java.lang +  
        + + java.lang.reflect +  
        + + java.net +  
        + + java.util +  
        + + java.util.jar +  
        + + java.util.logging +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/classes_index_additions.html b/docs/html/sdk/api_diff/3/changes/classes_index_additions.html new file mode 100644 index 0000000000000000000000000000000000000000..32a68e3117fd903a3fff840bbb72484cec13277f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/classes_index_additions.html @@ -0,0 +1,469 @@ + + + + + + + + + +Class Additions Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Classes +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +C +D +G +H +I +J +L +M +N +O +P +R +S +T +U +V + TOP +

        +ActivityInstrumentationTestCase2
        +ActivityManager.RunningAppProcessInfo
        +AlphabetIndexer
        +AssetFileDescriptor.AutoCloseInputStream
        +AssetFileDescriptor.AutoCloseOutputStream
        +AsyncTask
        +AsyncTask.Status
        +AudioFormat
        +AudioRecord
        +AudioRecord.OnRecordPositionUpdateListener
        +AudioTrack
        +AudioTrack.OnPlaybackPositionUpdateListener
        + +
        C  +A +D +G +H +I +J +L +M +N +O +P +R +S +T +U +V + TOP +

        +Chronometer.OnChronometerTickListener
        +ConfigurationInfo
        + +
        D  +A +C +G +H +I +J +L +M +N +O +P +R +S +T +U +V + TOP +

        +DexClassLoader
        + +
        G  +A +C +D +H +I +J +L +M +N +O +P +R +S +T +U +V + TOP +

        +GeomagneticField
        +GestureDetector.OnDoubleTapListener
        +GLSurfaceView
        +GLSurfaceView.EGLConfigChooser
        +GLSurfaceView.GLWrapper
        +GLSurfaceView.Renderer
        +GpsSatellite
        +GpsStatus
        +GpsStatus.Listener
        + +
        H  +A +C +D +G +I +J +L +M +N +O +P +R +S +T +U +V + TOP +

        +Handler.Callback
        +HapticFeedbackConstants
        +HorizontalScrollView
        + +
        I  +A +C +D +G +H +J +L +M +N +O +P +R +S +T +U +V + TOP +

        +InputType
        +IntentService
        + +
        J  +A +C +D +G +H +I +L +M +N +O +P +R +S +T +U +V + TOP +

        +JetPlayer
        +JetPlayer.OnJetEventListener
        + +
        L  +A +C +D +G +H +I +J +M +N +O +P +R +S +T +U +V + TOP +

        +LauncherActivity.IconResizer
        +LauncherActivity.ListItem
        +LiveFolders
        + +
        M  +A +C +D +G +H +I +J +L +N +O +P +R +S +T +U +V + TOP +

        +MediaPlayer.OnInfoListener
        +MediaPlayer.OnVideoSizeChangedListener
        +MediaRecorder.OnErrorListener
        +MediaRecorder.OnInfoListener
        +MediaRecorder.VideoEncoder
        +MediaRecorder.VideoSource
        + +
        N  +A +C +D +G +H +I +J +L +M +O +P +R +S +T +U +V + TOP +

        +NeighboringCellInfo
        +NoCopySpan
        +NoCopySpan.Concrete
        + +
        O  +A +C +D +G +H +I +J +L +M +N +P +R +S +T +U +V + TOP +

        +OrientationEventListener
        + +
        P  +A +C +D +G +H +I +J +L +M +N +O +R +S +T +U +V + TOP +

        +ParcelableSpan
        +PluginData
        +PrintStreamPrinter
        +ProviderTestCase2
        + +
        R  +A +C +D +G +H +I +J +L +M +N +O +P +S +T +U +V + TOP +

        +R.bool
        +R.integer
        +ResultReceiver
        + +
        S  +A +C +D +G +H +I +J +L +M +N +O +P +R +T +U +V + TOP +

        +SectionIndexer
        +Sensor
        +SensorEvent
        +SensorEventListener
        +Settings.Secure
        +SlidingDrawer
        +SlidingDrawer.OnDrawerCloseListener
        +SlidingDrawer.OnDrawerOpenListener
        +SlidingDrawer.OnDrawerScrollListener
        + +
        T  +A +C +D +G +H +I +J +L +M +N +O +P +R +S +U +V + TOP +

        +TextView.OnEditorActionListener
        + +
        U  +A +C +D +G +H +I +J +L +M +N +O +P +R +S +T +V + TOP +

        +UpdateAppearance
        +UserDictionary
        +UserDictionary.Words
        + +
        V  +A +C +D +G +H +I +J +L +M +N +O +P +R +S +T +U + TOP +

        +ViewDebug.CapturedViewProperty
        +ViewTreeObserver.OnScrollChangedListener
        +Visibility
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/classes_index_all.html b/docs/html/sdk/api_diff/3/changes/classes_index_all.html new file mode 100644 index 0000000000000000000000000000000000000000..5815c29ca5a544edb21c4dba6dccc0cd983268a5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/classes_index_all.html @@ -0,0 +1,963 @@ + + + + + + + + + +Class Differences Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +Classes +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +AbsListView
        +AbsoluteLayout
        +AbsoluteSizeSpan
        +AbsSeekBar
        +Activity
        +ActivityInfo
        +ActivityInstrumentationTestCase
        +ActivityInstrumentationTestCase2
        +ActivityManager
        +ActivityManager.RunningAppProcessInfo
        +AlarmManager
        +AlertDialog
        +AlignmentSpan.Standard
        +AlphabetIndexer
        +Animation
        +Annotation
        +ArrayAdapter
        +ArrowKeyMovementMethod
        +AssetFileDescriptor
        +AssetFileDescriptor.AutoCloseInputStream
        +AssetFileDescriptor.AutoCloseOutputStream
        +AsyncTask
        +AsyncTask.Status
        +AudioFormat
        +AudioManager
        +AudioRecord
        +AudioRecord.OnRecordPositionUpdateListener
        +AudioTrack
        +AudioTrack.OnPlaybackPositionUpdateListener
        +AutoCompleteTextView
        +AutoText
        + +
        B  +A +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +BackgroundColorSpan
        +BaseKeyListener
        +Binder
        +Bitmap
        +BroadcastReceiver
        +Browser
        +Build
        +BulletSpan
        + +
        C  +A +B +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Camera
        +Canvas
        +Character.UnicodeBlock
        +Chronometer
        +Chronometer.OnChronometerTickListener
        +Class
        +ClickableSpan
        +Configuration
        +ConfigurationInfo
        +ConnectivityManager
        +Contacts.Intents
        +Contacts.Intents.Insert
        +Contacts.PeopleColumns
        +ContentProvider
        +ContentResolver
        +Context
        +Cursor
        +CursorAdapter
        +CursorWrapper
        + +
        D  +A +B +C +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +DatabaseUtils
        +Date
        +DateKeyListener
        +DateTimeKeyListener
        +Debug
        +DexClassLoader
        +DexFile
        +DialerKeyListener
        +DialogInterface
        +DialogPreference
        +DigitsKeyListener
        +Drawable
        +DynamicDrawableSpan
        + +
        E  +A +B +C +D +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Environment
        + +
        F  +A +B +C +D +E +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +ForegroundColorSpan
        + +
        G  +A +B +C +D +E +F +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +GeomagneticField
        +GestureDetector
        +GestureDetector.OnDoubleTapListener
        +GestureDetector.SimpleOnGestureListener
        +GLSurfaceView
        +GLSurfaceView.EGLConfigChooser
        +GLSurfaceView.GLWrapper
        +GLSurfaceView.Renderer
        +GpsSatellite
        +GpsStatus
        +GpsStatus.Listener
        +Gravity
        +GridView
        + +
        H  +A +B +C +D +E +F +G +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Handler
        +Handler.Callback
        +HapticFeedbackConstants
        +HorizontalScrollView
        + +
        I  +A +B +C +D +E +F +G +H +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +IBinder
        +ImageSpan
        +InputType
        +Instrumentation
        +InstrumentationTestCase
        +Intent
        +IntentService
        + +
        J  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +JetPlayer
        +JetPlayer.OnJetEventListener
        + +
        K  +A +B +C +D +E +F +G +H +I +J +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +KeyCharacterMap
        +KeyEvent
        +KeyListener
        + +
        L  +A +B +C +D +E +F +G +H +I +J +K +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +LauncherActivity
        +LauncherActivity.IconResizer
        +LauncherActivity.ListItem
        +LeadingMarginSpan.Standard
        +Level
        +ListView
        +LiveFolders
        +Location
        +LocationManager
        +LogManager
        +Looper
        + +
        M  +A +B +C +D +E +F +G +H +I +J +K +L +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Manifest.permission
        +MaskFilterSpan
        +MediaPlayer
        +MediaPlayer.OnInfoListener
        +MediaPlayer.OnVideoSizeChangedListener
        +MediaRecorder
        +MediaRecorder.OnErrorListener
        +MediaRecorder.OnInfoListener
        +MediaRecorder.OutputFormat
        +MediaRecorder.VideoEncoder
        +MediaRecorder.VideoSource
        +MediaStore
        +MediaStore.Audio.AlbumColumns
        +MediaStore.Audio.Media
        +MediaStore.Images.Media
        +MediaStore.Video
        +MediaStore.Video.VideoColumns
        +Menu
        +MetaKeyKeyListener
        +MockPackageManager
        +MotionEvent
        +MovementMethod
        +MultiTapKeyListener
        + +
        N  +A +B +C +D +E +F +G +H +I +J +K +L +M +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +NeighboringCellInfo
        +NetworkInfo
        +NoCopySpan
        +NoCopySpan.Concrete
        + +
        O  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +P +Q +R +S +T +U +V +W +Z + TOP +

        +OrientationEventListener
        +OrientationListener
        + +
        P  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +Q +R +S +T +U +V +W +Z + TOP +

        +Pack200.Packer
        +Pack200.Unpacker
        +PackageInfo
        +PackageManager
        +Parcel
        +ParcelableSpan
        +ParcelFileDescriptor
        +PendingIntent
        +PhoneNumberUtils
        +PluginData
        +PopupWindow
        +PopupWindow.OnDismissListener
        +PrintStreamPrinter
        +ProgressBar
        +ProviderTestCase
        +ProviderTestCase2
        +Proxy
        + +
        Q  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +R +S +T +U +V +W +Z + TOP +

        +QuoteSpan
        +QwertyKeyListener
        + +
        R  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +S +T +U +V +W +Z + TOP +

        +R.attr
        +R.bool
        +R.drawable
        +R.id
        +R.integer
        +R.string
        +R.style
        +RasterizerSpan
        +Rect
        +RectF
        +RelativeSizeSpan
        +RemoteViews
        +RemoteViews.ActionException
        +ResourceCursorAdapter
        +Resources
        +ResultReceiver
        +RingtoneManager
        +RotateDrawable
        + +
        S  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +T +U +V +W +Z + TOP +

        +ScaleDrawable
        +ScaleXSpan
        +Scroller
        +ScrollingMovementMethod
        +SectionIndexer
        +Sensor
        +SensorEvent
        +SensorEventListener
        +SensorListener
        +SensorManager
        +Settings
        +Settings.Secure
        +Settings.System
        +Shape
        +SimpleCursorAdapter
        +SlidingDrawer
        +SlidingDrawer.OnDrawerCloseListener
        +SlidingDrawer.OnDrawerOpenListener
        +SlidingDrawer.OnDrawerScrollListener
        +SmsMessage
        +Socket
        +SoundPool
        +Spanned
        +SpanWatcher
        +SparseIntArray
        +SQLiteDatabase
        +StrikethroughSpan
        +String
        +StyleSpan
        +SubscriptSpan
        +SuperscriptSpan
        + +
        T  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +U +V +W +Z + TOP +

        +TelephonyManager
        +TestMethod
        +TestSuiteBuilder
        +TextAppearanceSpan
        +TextKeyListener
        +TextUtils
        +TextView
        +TextView.OnEditorActionListener
        +TextWatcher
        +TimeKeyListener
        +TimeUtils
        +Touch
        +TouchUtils
        +Transformation
        +TransitionDrawable
        +TypedArray
        +TypefaceSpan
        + +
        U  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +V +W +Z + TOP +

        +UnderlineSpan
        +UpdateAppearance
        +UpdateLayout
        +UrlInterceptHandler
        +UrlInterceptRegistry
        +URLSpan
        +URLUtil
        +UserDictionary
        +UserDictionary.Words
        + +
        V  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +W +Z + TOP +

        +View
        +ViewConfiguration
        +ViewDebug
        +ViewDebug.CapturedViewProperty
        +ViewGroup
        +ViewParent
        +ViewTreeObserver
        +ViewTreeObserver.OnScrollChangedListener
        +Visibility
        +VMDebug
        + +
        W  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +Z + TOP +

        +WebHistoryItem
        +WebSettings
        +WebView
        +WifiManager
        +Window
        +WindowManager.LayoutParams
        + +
        Z  +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W + TOP +

        +Zygote
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/classes_index_changes.html b/docs/html/sdk/api_diff/3/changes/classes_index_changes.html new file mode 100644 index 0000000000000000000000000000000000000000..58d4edcbc8a75c11f67e0994a83e8d21a8377482 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/classes_index_changes.html @@ -0,0 +1,846 @@ + + + + + + + + + +Class Changes Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Classes +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +AbsListView
        +AbsoluteLayout
        +AbsoluteSizeSpan
        +AbsSeekBar
        +Activity
        +ActivityInfo
        +ActivityInstrumentationTestCase
        +ActivityManager
        +AlarmManager
        +AlertDialog
        +AlignmentSpan.Standard
        +Animation
        +Annotation
        +ArrayAdapter
        +ArrowKeyMovementMethod
        +AssetFileDescriptor
        +AudioManager
        +AutoCompleteTextView
        +AutoText
        + +
        B  +A +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +BackgroundColorSpan
        +BaseKeyListener
        +Binder
        +Bitmap
        +BroadcastReceiver
        +Browser
        +Build
        +BulletSpan
        + +
        C  +A +B +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Camera
        +Canvas
        +Character.UnicodeBlock
        +Chronometer
        +Class
        +ClickableSpan
        +Configuration
        +ConnectivityManager
        +Contacts.Intents
        +Contacts.Intents.Insert
        +Contacts.PeopleColumns
        +ContentProvider
        +ContentResolver
        +Context
        +Cursor
        +CursorAdapter
        +CursorWrapper
        + +
        D  +A +B +C +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +DatabaseUtils
        +Date
        +DateKeyListener
        +DateTimeKeyListener
        +Debug
        +DexFile
        +DialerKeyListener
        +DialogInterface
        +DialogPreference
        +DigitsKeyListener
        +Drawable
        +DynamicDrawableSpan
        + +
        E  +A +B +C +D +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Environment
        + +
        F  +A +B +C +D +E +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +ForegroundColorSpan
        + +
        G  +A +B +C +D +E +F +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +GestureDetector
        +GestureDetector.SimpleOnGestureListener
        +Gravity
        +GridView
        + +
        H  +A +B +C +D +E +F +G +I +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Handler
        + +
        I  +A +B +C +D +E +F +G +H +K +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +IBinder
        +ImageSpan
        +Instrumentation
        +InstrumentationTestCase
        +Intent
        + +
        K  +A +B +C +D +E +F +G +H +I +L +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +KeyCharacterMap
        +KeyEvent
        +KeyListener
        + +
        L  +A +B +C +D +E +F +G +H +I +K +M +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +LauncherActivity
        +LeadingMarginSpan.Standard
        +Level
        +ListView
        +Location
        +LocationManager
        +LogManager
        +Looper
        + +
        M  +A +B +C +D +E +F +G +H +I +K +L +N +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +Manifest.permission
        +MaskFilterSpan
        +MediaPlayer
        +MediaRecorder
        +MediaRecorder.OutputFormat
        +MediaStore
        +MediaStore.Audio.AlbumColumns
        +MediaStore.Audio.Media
        +MediaStore.Images.Media
        +MediaStore.Video
        +MediaStore.Video.VideoColumns
        +Menu
        +MetaKeyKeyListener
        +MockPackageManager
        +MotionEvent
        +MovementMethod
        +MultiTapKeyListener
        + +
        N  +A +B +C +D +E +F +G +H +I +K +L +M +O +P +Q +R +S +T +U +V +W +Z + TOP +

        +NetworkInfo
        + +
        O  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +Q +R +S +T +U +V +W +Z + TOP +

        +OrientationListener
        + +
        P  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +Q +R +S +T +U +V +W +Z + TOP +

        +Pack200.Packer
        +Pack200.Unpacker
        +PackageInfo
        +PackageManager
        +Parcel
        +ParcelFileDescriptor
        +PendingIntent
        +PhoneNumberUtils
        +PopupWindow
        +PopupWindow.OnDismissListener
        +ProgressBar
        +ProviderTestCase
        +Proxy
        + +
        Q  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +R +S +T +U +V +W +Z + TOP +

        +QuoteSpan
        +QwertyKeyListener
        + +
        R  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +S +T +U +V +W +Z + TOP +

        +R.attr
        +R.drawable
        +R.id
        +R.string
        +R.style
        +RasterizerSpan
        +Rect
        +RectF
        +RelativeSizeSpan
        +RemoteViews
        +RemoteViews.ActionException
        +ResourceCursorAdapter
        +Resources
        +RingtoneManager
        +RotateDrawable
        + +
        S  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +T +U +V +W +Z + TOP +

        +ScaleDrawable
        +ScaleXSpan
        +Scroller
        +ScrollingMovementMethod
        +SensorListener
        +SensorManager
        +Settings
        +Settings.System
        +Shape
        +SimpleCursorAdapter
        +SmsMessage
        +Socket
        +SoundPool
        +Spanned
        +SpanWatcher
        +SparseIntArray
        +SQLiteDatabase
        +StrikethroughSpan
        +String
        +StyleSpan
        +SubscriptSpan
        +SuperscriptSpan
        + +
        T  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +U +V +W +Z + TOP +

        +TelephonyManager
        +TestMethod
        +TestSuiteBuilder
        +TextAppearanceSpan
        +TextKeyListener
        +TextUtils
        +TextView
        +TextWatcher
        +TimeKeyListener
        +TimeUtils
        +Touch
        +TouchUtils
        +Transformation
        +TransitionDrawable
        +TypedArray
        +TypefaceSpan
        + +
        U  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +V +W +Z + TOP +

        +UnderlineSpan
        +UpdateLayout
        +UrlInterceptHandler
        +UrlInterceptRegistry
        +URLSpan
        +URLUtil
        + +
        V  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +W +Z + TOP +

        +View
        +ViewConfiguration
        +ViewDebug
        +ViewGroup
        +ViewParent
        +ViewTreeObserver
        +VMDebug
        + +
        W  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +Z + TOP +

        +WebHistoryItem
        +WebSettings
        +WebView
        +WifiManager
        +Window
        +WindowManager.LayoutParams
        + +
        Z  +A +B +C +D +E +F +G +H +I +K +L +M +N +O +P +Q +R +S +T +U +V +W + TOP +

        +Zygote
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/classes_index_removals.html b/docs/html/sdk/api_diff/3/changes/classes_index_removals.html new file mode 100644 index 0000000000000000000000000000000000000000..bc5e2e821957abf36496bd53c2c21cc5cf1c33a3 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/classes_index_removals.html @@ -0,0 +1,62 @@ + + + + + + + + + +Class Removals Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Classes +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/constructors_index_additions.html b/docs/html/sdk/api_diff/3/changes/constructors_index_additions.html new file mode 100644 index 0000000000000000000000000000000000000000..0dff7fe55a9610924a8147f34ced00361c8d7562 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/constructors_index_additions.html @@ -0,0 +1,409 @@ + + + + + + + + + +Constructor Additions Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Constructors +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +D +F +G +H +I +K +L +O +Q +R +S +T +U + TOP +

        +AbsoluteSizeSpan +(Parcel) constructor
        +AlignmentSpan.Standard +(Parcel) constructor
        +Annotation +(Parcel) constructor
        + +
        B  +A +D +F +G +H +I +K +L +O +Q +R +S +T +U + TOP +

        +BackgroundColorSpan +(Parcel) constructor
        +BulletSpan +(Parcel) constructor
        + +
        D  +A +B +F +G +H +I +K +L +O +Q +R +S +T +U + TOP +

        +DynamicDrawableSpan +(int) constructor
        + +
        F  +A +B +D +G +H +I +K +L +O +Q +R +S +T +U + TOP +

        +ForegroundColorSpan +(Parcel) constructor
        + +
        G  +A +B +D +F +H +I +K +L +O +Q +R +S +T +U + TOP +

        +GestureDetector
        +  GestureDetector +(Context, OnGestureListener) constructor
        +  GestureDetector +(Context, OnGestureListener, Handler) constructor
        + +
        H  +A +B +D +F +G +I +K +L +O +Q +R +S +T +U + TOP +

        +Handler
        +  Handler +(Callback) constructor
        +  Handler +(Looper, Callback) constructor
        + +
        I  +A +B +D +F +G +H +K +L +O +Q +R +S +T +U + TOP +

        +ImageSpan
        +  ImageSpan +(Context, Uri, int) constructor
        +  ImageSpan +(Context, int, int) constructor
        +  ImageSpan +(Bitmap, int) constructor
        +  ImageSpan +(Drawable, int) constructor
        +  ImageSpan +(Drawable, String, int) constructor
        + +
        K  +A +B +D +F +G +H +I +L +O +Q +R +S +T +U + TOP +

        +KeyEvent
        +  KeyEvent +(KeyEvent) constructor
        +  KeyEvent +(long, String, int, int) constructor
        + +
        L  +A +B +D +F +G +H +I +K +O +Q +R +S +T +U + TOP +

        +LeadingMarginSpan.Standard +(Parcel) constructor
        + +
        O  +A +B +D +F +G +H +I +K +L +Q +R +S +T +U + TOP +

        +OrientationListener +(Context, int) constructor
        + +
        Q  +A +B +D +F +G +H +I +K +L +O +R +S +T +U + TOP +

        +QuoteSpan +(Parcel) constructor
        + +
        R  +A +B +D +F +G +H +I +K +L +O +Q +S +T +U + TOP +

        +RelativeSizeSpan +(Parcel) constructor
        +RemoteViews.ActionException +(Exception) constructor
        +ResourceCursorAdapter +(Context, int, Cursor, boolean) constructor
        + +
        S  +A +B +D +F +G +H +I +K +L +O +Q +R +T +U + TOP +

        +ScaleXSpan +(Parcel) constructor
        +StrikethroughSpan +(Parcel) constructor
        +StyleSpan +(Parcel) constructor
        +SubscriptSpan +(Parcel) constructor
        +SuperscriptSpan +(Parcel) constructor
        + +
        T  +A +B +D +F +G +H +I +K +L +O +Q +R +S +U + TOP +

        +TestMethod
        +  TestMethod +(String, Class<TestCase>) constructor
        +  TestMethod +(TestCase) constructor
        +TextAppearanceSpan +(Parcel) constructor
        +TransitionDrawable +(Drawable[]) constructor
        +TypefaceSpan +(Parcel) constructor
        + +
        U  +A +B +D +F +G +H +I +K +L +O +Q +R +S +T + TOP +

        +UnderlineSpan +(Parcel) constructor
        +URLSpan +(Parcel) constructor
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/constructors_index_all.html b/docs/html/sdk/api_diff/3/changes/constructors_index_all.html new file mode 100644 index 0000000000000000000000000000000000000000..49ad673c48aa56552668a88c761b4d4f0c9c2c0a --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/constructors_index_all.html @@ -0,0 +1,514 @@ + + + + + + + + + +Constructor Differences Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +Constructors +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +D +F +G +H +I +K +L +N +O +Q +R +S +T +U +V + TOP +

        +AbsoluteSizeSpan +(Parcel) constructor
        +AlignmentSpan.Standard +(Parcel) constructor
        +Annotation +(Parcel) constructor
        + +
        B  +A +D +F +G +H +I +K +L +N +O +Q +R +S +T +U +V + TOP +

        +BackgroundColorSpan +(Parcel) constructor
        +BulletSpan +(Parcel) constructor
        + +
        D  +A +B +F +G +H +I +K +L +N +O +Q +R +S +T +U +V + TOP +

        +Date
        +  Date +() constructor
        +  Date +(int, int, int, int, int, int) constructor
        +DynamicDrawableSpan +(int) constructor
        + +
        F  +A +B +D +G +H +I +K +L +N +O +Q +R +S +T +U +V + TOP +

        +ForegroundColorSpan +(Parcel) constructor
        + +
        G  +A +B +D +F +H +I +K +L +N +O +Q +R +S +T +U +V + TOP +

        +GestureDetector
        +  GestureDetector +(Context, OnGestureListener) constructor
        +  GestureDetector +(Context, OnGestureListener, Handler) constructor
        +  GestureDetector +(OnGestureListener) constructor
        +  GestureDetector +(OnGestureListener, Handler) constructor
        + +
        H  +A +B +D +F +G +I +K +L +N +O +Q +R +S +T +U +V + TOP +

        +Handler
        +  Handler +(Callback) constructor
        +  Handler +(Looper, Callback) constructor
        + +
        I  +A +B +D +F +G +H +K +L +N +O +Q +R +S +T +U +V + TOP +

        +ImageSpan
        +  ImageSpan +(Context, Uri, int) constructor
        +  ImageSpan +(Context, int, int) constructor
        +  ImageSpan +(Bitmap, int) constructor
        +  ImageSpan +(Drawable, int) constructor
        +  ImageSpan +(Drawable, String, int) constructor
        + +
        K  +A +B +D +F +G +H +I +L +N +O +Q +R +S +T +U +V + TOP +

        +KeyEvent
        +  KeyEvent +(KeyEvent) constructor
        +  KeyEvent +(long, String, int, int) constructor
        + +
        L  +A +B +D +F +G +H +I +K +N +O +Q +R +S +T +U +V + TOP +

        +LeadingMarginSpan.Standard +(Parcel) constructor
        + +
        N  +A +B +D +F +G +H +I +K +L +O +Q +R +S +T +U +V + TOP +

        +NetworkInfo +(int) constructor
        + +
        O  +A +B +D +F +G +H +I +K +L +N +Q +R +S +T +U +V + TOP +

        +OrientationListener +(Context, int) constructor
        + +
        Q  +A +B +D +F +G +H +I +K +L +N +O +R +S +T +U +V + TOP +

        +QuoteSpan +(Parcel) constructor
        + +
        R  +A +B +D +F +G +H +I +K +L +N +O +Q +S +T +U +V + TOP +

        +RelativeSizeSpan +(Parcel) constructor
        +RemoteViews.ActionException +(Exception) constructor
        +ResourceCursorAdapter +(Context, int, Cursor, boolean) constructor
        + +
        S  +A +B +D +F +G +H +I +K +L +N +O +Q +R +T +U +V + TOP +

        +ScaleXSpan +(Parcel) constructor
        +Socket
        +  Socket +() constructor
        +  Socket +(String, int) constructor
        +  Socket +(String, int, InetAddress, int) constructor
        +  Socket +(Proxy) constructor
        +  Socket +(SocketImpl) constructor
        +StrikethroughSpan +(Parcel) constructor
        +String
        +  String +() constructor
        +  String +(byte[]) constructor
        +  String +(byte[], int) constructor
        +  String +(byte[], int, int) constructor
        +  String +(byte[], int, int, int) constructor
        +StyleSpan +(Parcel) constructor
        +SubscriptSpan +(Parcel) constructor
        +SuperscriptSpan +(Parcel) constructor
        + +
        T  +A +B +D +F +G +H +I +K +L +N +O +Q +R +S +U +V + TOP +

        +TestMethod
        +  TestMethod +(String, Class<TestCase>) constructor
        +  TestMethod +(TestCase) constructor
        +TextAppearanceSpan +(Parcel) constructor
        +TransitionDrawable +(Drawable[]) constructor
        +TypefaceSpan +(Parcel) constructor
        + +
        U  +A +B +D +F +G +H +I +K +L +N +O +Q +R +S +T +V + TOP +

        +UnderlineSpan +(Parcel) constructor
        +URLSpan +(Parcel) constructor
        + +
        V  +A +B +D +F +G +H +I +K +L +N +O +Q +R +S +T +U + TOP +

        +ViewConfiguration +() constructor
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/constructors_index_changes.html b/docs/html/sdk/api_diff/3/changes/constructors_index_changes.html new file mode 100644 index 0000000000000000000000000000000000000000..8ea3eec7b0342ede9966f8a07214893c02196357 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/constructors_index_changes.html @@ -0,0 +1,124 @@ + + + + + + + + + +Constructor Changes Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Constructors +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        D  +G +S +V + TOP +

        +Date
        +  Date +() constructor
        +  Date +(int, int, int, int, int, int) constructor
        + +
        G  +D +S +V + TOP +

        +GestureDetector
        +  GestureDetector +(OnGestureListener) constructor
        +  GestureDetector +(OnGestureListener, Handler) constructor
        + +
        S  +D +G +V + TOP +

        +Socket
        +  Socket +() constructor
        +  Socket +(String, int) constructor
        +  Socket +(String, int, InetAddress, int) constructor
        +  Socket +(Proxy) constructor
        +  Socket +(SocketImpl) constructor
        +String
        +  String +() constructor
        +  String +(byte[]) constructor
        +  String +(byte[], int) constructor
        +  String +(byte[], int, int) constructor
        +  String +(byte[], int, int, int) constructor
        + +
        V  +D +G +S + TOP +

        +ViewConfiguration +() constructor
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/constructors_index_removals.html b/docs/html/sdk/api_diff/3/changes/constructors_index_removals.html new file mode 100644 index 0000000000000000000000000000000000000000..8e591c1e3fd5108d338192e716d6edf85a07b04d --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/constructors_index_removals.html @@ -0,0 +1,68 @@ + + + + + + + + + +Constructor Removals Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Constructors +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        N  + TOP +

        +NetworkInfo +(int) constructor
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/dalvik.system.DexFile.html b/docs/html/sdk/api_diff/3/changes/dalvik.system.DexFile.html new file mode 100644 index 0000000000000000000000000000000000000000..ef3937c0a195858e7b8e0376d3fcf9679c054905 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/dalvik.system.DexFile.html @@ -0,0 +1,123 @@ + + + + + + + + + +dalvik.system.DexFile + + + + + + + + + + +
        +
        +
        +

        +Class dalvik.system.DexFile +

        + + +

        + + + + + + + + +
        Added Methods +
        + + DexFile loadDex(String, String, int) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/dalvik.system.VMDebug.html b/docs/html/sdk/api_diff/3/changes/dalvik.system.VMDebug.html new file mode 100644 index 0000000000000000000000000000000000000000..c7ee90942566cd04a2efa226d977c66e067da1d2 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/dalvik.system.VMDebug.html @@ -0,0 +1,130 @@ + + + + + + + + + +dalvik.system.VMDebug + + + + + + + + + + +
        +
        +
        +

        +Class dalvik.system.VMDebug +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + void dumpHprofData(String) +  
        + + boolean isDebuggingEnabled() +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/dalvik.system.Zygote.html b/docs/html/sdk/api_diff/3/changes/dalvik.system.Zygote.html new file mode 100644 index 0000000000000000000000000000000000000000..d26e9e64abe2acc997bbfa31d6cfd10363ecc3e0 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/dalvik.system.Zygote.html @@ -0,0 +1,187 @@ + + + + + + + + + +dalvik.system.Zygote + + + + + + + + + + +
        +
        +
        +

        +Class dalvik.system.Zygote +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + int forkAndSpecialize(int, int, int[], int, int[][]) +  
        + + int forkSystemServer(int, int, int[], int, int[][]) +  
        +  +

        + + + + + + + + + + + + + + +
        Changed Methods +
        + + int forkAndSpecialize(int, int, int[], boolean, int[][]) + +Now deprecated.
        +
         
        + + int forkSystemServer(int, int, int[], boolean, int[][]) + +Now deprecated.
        +
         
        +  + +

        + + + + + + + + + + + + + + + + +
        Added Fields +
        + + int DEBUG_ENABLE_ASSERT +  
        + + int DEBUG_ENABLE_CHECKJNI +  
        + + int DEBUG_ENABLE_DEBUGGER +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/fields_index_additions.html b/docs/html/sdk/api_diff/3/changes/fields_index_additions.html new file mode 100644 index 0000000000000000000000000000000000000000..c2c3b494595c4738bcab821f162526938be4abb4 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/fields_index_additions.html @@ -0,0 +1,1129 @@ + + + + + + + + + +Field Additions Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Fields +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +ACCELEROMETER_ROTATION +
        +ACTION_AIRPLANE_MODE_SETTINGS +
        +ACTION_APPLICATION_DEVELOPMENT_SETTINGS +
        +ACTION_AUDIO_BECOMING_NOISY +
        +ACTION_BACKGROUND_DATA_SETTING_CHANGED +
        +ACTION_DATA_ROAMING_SETTINGS +
        +ACTION_IMAGE_CAPTURE +
        +ACTION_INPUT_METHOD_CHANGED +
        +ACTION_INPUT_METHOD_SETTINGS +
        +ACTION_INTERNAL_STORAGE_SETTINGS +
        +ACTION_MANAGE_APPLICATIONS_SETTINGS +
        +ACTION_MEDIA_CHECKING +
        +ACTION_MEDIA_NOFS +
        +ACTION_MEMORY_CARD_SETTINGS +
        +ACTION_NETWORK_OPERATOR_SETTINGS +
        +ACTION_OUTSIDE +
        +ACTION_PACKAGE_DATA_CLEARED +
        +ACTION_PACKAGE_REPLACED +
        +ACTION_PHONE_STATE_CHANGED +
        +ACTION_QUICK_LAUNCH_SETTINGS +
        +ACTION_SEARCH_LONG_PRESS +
        +ACTION_SYNC_SETTINGS +
        +ACTION_SYSTEM_TUTORIAL +
        +ACTION_USER_DICTIONARY_SETTINGS +
        +ACTION_USER_PRESENT +
        +ACTION_VIDEO_CAPTURE +
        +ACTION_WIFI_IP_SETTINGS +
        +addToDictionary +
        +ALIGN_BASELINE +
        +ALIGN_BOTTOM +
        +allowSingleTap +
        +animateOnClick +
        +AXIS_CLIP +
        +AXIS_MINUS_X +
        +AXIS_MINUS_Y +
        +AXIS_MINUS_Z +
        +AXIS_X +
        +AXIS_Y +
        +AXIS_Z +
        + +
        B  +A +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +backgroundDimEnabled +
        +BIND_APPWIDGET +
        +BIND_INPUT_METHOD +
        +BOOKMARK +
        +bottomOffset +
        +BUCKET_DISPLAY_NAME +
        +BUCKET_ID +
        +BUTTON_NEGATIVE +
        +BUTTON_NEUTRAL +
        +BUTTON_POSITIVE +
        + +
        C  +A +B +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +candidatesArea +
        +candidatesTextStyleSpans +
        +CAP_MODE_CHARACTERS +
        +CAP_MODE_SENTENCES +
        +CAP_MODE_WORDS +
        +CATEGORY_INFO +
        +CLIP_HORIZONTAL +
        +CLIP_VERTICAL +
        +closeButton +
        +codes +
        +configPreferences +
        +configure +
        +content +
        +copy +
        +copyUrl +
        +CREATOR
        + in  +android.content.res.AssetFileDescriptor +
        + in  +android.graphics.RectF +
        +cut +
        + +
        D  +A +B +C +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +dark_header +
        +DEBUG_ENABLE_ASSERT +
        +DEBUG_ENABLE_CHECKJNI +
        +DEBUG_ENABLE_DEBUGGER +
        +dialog_alert_title +
        +DISPLAY +
        +DISPLAY_CLIP_HORIZONTAL +
        +DISPLAY_CLIP_VERTICAL +
        +dropDownAnchor +
        +dropDownWidth +
        + +
        E  +A +B +C +D +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +editorExtras +
        +EXTRA_APPLICATION_ID +
        +EXTRA_CREATE_DESCRIPTION +
        +EXTRA_DATA_REMOVED +
        +EXTRA_FINISH_ON_COMPLETION +
        +EXTRA_FORCE_CREATE +
        +EXTRA_INCOMING_NUMBER +
        +EXTRA_MAX_BYTES +
        +EXTRA_MEDIA_ALBUM +
        +EXTRA_MEDIA_ARTIST +
        +EXTRA_MEDIA_FOCUS +
        +EXTRA_MEDIA_TITLE +
        +EXTRA_OUTPUT +
        +EXTRA_REPLACING +
        +EXTRA_SCREEN_ORIENTATION +
        +EXTRA_STATE +
        +EXTRA_STATE_IDLE +
        +EXTRA_STATE_OFFHOOK +
        +EXTRA_STATE_RINGING +
        +EXTRA_VIDEO_QUALITY +
        +extractArea +
        + +
        F  +A +B +C +D +E +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +fastScrollEnabled +
        +fillEnabled +
        +FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET +
        +FLAG_ACTIVITY_NO_USER_ACTION +
        +FLAG_ACTIVITY_REORDER_TO_FRONT +
        +FLAG_ALT_FOCUSABLE_IM +
        +FLAG_EDITOR_ACTION +
        +FLAG_FROM_SYSTEM +
        +FLAG_KEEP_TOUCH_MODE +
        +FLAG_NO_HISTORY +
        +FLAG_SOFT_KEYBOARD +
        +FLAG_UPDATE_CURRENT +
        +FLAG_WATCH_OUTSIDE_TOUCH +
        +footerDividersEnabled +
        +FORMAT_JAPAN +
        +FX_KEYPRESS_DELETE +
        +FX_KEYPRESS_RETURN +
        +FX_KEYPRESS_SPACEBAR +
        +FX_KEYPRESS_STANDARD +
        + +
        G  +A +B +C +D +E +F +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +GET_CONFIGURATIONS +
        +GET_UNINSTALLED_PACKAGES +
        + +
        H  +A +B +C +D +E +F +G +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +handle +
        +HAPTIC_FEEDBACK_ENABLED
        + in  +android.provider.Settings.System +
        + in  +android.view.View +
        +hapticFeedbackEnabled +
        +hardKeyboardHidden +
        +HARDKEYBOARDHIDDEN_NO +
        +HARDKEYBOARDHIDDEN_UNDEFINED +
        +HARDKEYBOARDHIDDEN_YES +
        +headerDividersEnabled +
        +horizontalGap +
        + +
        I  +A +B +C +D +E +F +G +H +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +ic_btn_speak_now +
        +iconPreview +
        +imeActionId +
        +imeActionLabel +
        +imeExtractEnterAnimation +
        +imeExtractExitAnimation +
        +imeFullscreenBackground +
        +imeOptions +
        +initialLayout +
        +innerRadius +
        +INPUT_METHOD_FROM_FOCUSABLE +
        +INPUT_METHOD_NEEDED +
        +INPUT_METHOD_NOT_NEEDED +
        +INPUT_METHOD_SERVICE +
        +inputArea +
        +inputExtractEditText +
        +inputType +
        +INSTALL_FAILED_CONFLICTING_PROVIDER +
        +INTENT_ACTION_MEDIA_SEARCH +
        +INTENT_ACTION_STILL_IMAGE_CAMERA +
        +INTENT_ACTION_VIDEO_CAMERA +
        +INTERVAL_DAY +
        +INTERVAL_FIFTEEN_MINUTES +
        +INTERVAL_HALF_DAY +
        +INTERVAL_HALF_HOUR +
        +INTERVAL_HOUR +
        +isDefault +
        +isModifier +
        +isRepeatable +
        +isScrollContainer +
        +isSticky +
        + +
        K  +A +B +C +D +E +F +G +H +I +L +M +N +P +R +S +T +U +V +W + TOP +

        +KEY_LOCATION_CHANGED +
        +KEY_PROVIDER_ENABLED +
        +KEY_STATUS_CHANGED +
        +keyBackground +
        +keyboardMode +
        +keyboardView +
        +KEYCODE_MEDIA_FAST_FORWARD +
        +KEYCODE_MEDIA_NEXT +
        +KEYCODE_MEDIA_PLAY_PAUSE +
        +KEYCODE_MEDIA_PREVIOUS +
        +KEYCODE_MEDIA_REWIND +
        +KEYCODE_MEDIA_STOP +
        +KEYCODE_MUTE +
        +keyEdgeFlags +
        +keyHeight +
        +keyIcon +
        +keyLabel +
        +keyOutputText +
        +keyPreviewHeight +
        +keyPreviewLayout +
        +keyPreviewOffset +
        +keyTextColor +
        +keyTextSize +
        +keyWidth +
        + +
        L  +A +B +C +D +E +F +G +H +I +K +M +N +P +R +S +T +U +V +W + TOP +

        +labelTextSize +
        +LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED +
        + +
        M  +A +B +C +D +E +F +G +H +I +K +L +N +P +R +S +T +U +V +W + TOP +

        +MEDIA_CHECKING +
        +MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK +
        +MEDIA_INFO_BAD_INTERLEAVING +
        +MEDIA_INFO_NOT_SEEKABLE +
        +MEDIA_INFO_UNKNOWN +
        +MEDIA_INFO_VIDEO_TRACK_LAGGING +
        +MEDIA_NOFS +
        +MEDIA_RECORDER_ERROR_UNKNOWN +
        +MEDIA_RECORDER_INFO_MAX_DURATION_REACHED +
        +MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED +
        +MEDIA_RECORDER_INFO_UNKNOWN +
        +MODE_APPEND +
        +MOUNT_FORMAT_FILESYSTEMS +
        +mVerticalAlignment +
        + +
        N  +A +B +C +D +E +F +G +H +I +K +L +M +P +R +S +T +U +V +W + TOP +

        +noHistory +
        +NUMBER_OF_SONGS_FOR_ARTIST +
        + +
        P  +A +B +C +D +E +F +G +H +I +K +L +M +N +R +S +T +U +V +W + TOP +

        +paste +
        +PHONETIC_NAME
        + in  +android.provider.Contacts.Intents.Insert +
        + in  +android.provider.Contacts.PeopleColumns +
        +popupCharacters +
        +popupKeyboard +
        +popupLayout +
        +privateImeOptions +
        + +
        R  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +S +T +U +V +W + TOP +

        +RAW_AMR +
        +reqFiveWayNav +
        +reqHardKeyboard +
        +reqKeyboardType +
        +reqNavigation +
        +reqTouchScreen +
        +ROUTE_BLUETOOTH_A2DP +
        +ROUTE_BLUETOOTH_SCO +
        +rowEdgeFlags +
        + +
        S  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +T +U +V +W + TOP +

        +SCREEN_BRIGHTNESS_CHANGED +
        +SCREEN_ORIENTATION_CHANGED +
        +screenBrightness +
        +screenOrientation +
        +SECONDARY_EMAIL +
        +SECONDARY_EMAIL_TYPE +
        +SECONDARY_PHONE +
        +SECONDARY_PHONE_TYPE +
        +selectAll +
        +settingsActivity +
        +sharedUserId +
        +sharedUserLabel
        + in  +android.R.attr +
        + in  +android.content.pm.PackageInfo +
        +SHOW_OR_CREATE_CONTACT +
        +smoothScrollbar +
        +SOFT_INPUT_ADJUST_PAN +
        +SOFT_INPUT_ADJUST_RESIZE +
        +SOFT_INPUT_ADJUST_UNSPECIFIED +
        +SOFT_INPUT_IS_FORWARD_NAVIGATION +
        +SOFT_INPUT_MASK_ADJUST +
        +SOFT_INPUT_MASK_STATE +
        +SOFT_INPUT_MODE_CHANGED +
        +SOFT_INPUT_STATE_ALWAYS_HIDDEN +
        +SOFT_INPUT_STATE_ALWAYS_VISIBLE +
        +SOFT_INPUT_STATE_HIDDEN +
        +SOFT_INPUT_STATE_UNCHANGED +
        +SOFT_INPUT_STATE_UNSPECIFIED +
        +SOFT_INPUT_STATE_VISIBLE +
        +softInputMode
        + in  +android.content.pm.ActivityInfo +
        + in  +android.view.WindowManager.LayoutParams +
        +SPAN_COMPOSING +
        +SPAN_INTERMEDIATE +
        +SPAN_POINT_MARK_MASK +
        +startSelectingText +
        +state_long_pressable +
        +stopSelectingText +
        +STREAM_NOTIFICATION +
        +STRETCH_SPACING_UNIFORM +
        +switchInputMethod +
        + +
        T  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +U +V +W + TOP +

        +TERTIARY_EMAIL +
        +TERTIARY_EMAIL_TYPE +
        +TERTIARY_PHONE +
        +TERTIARY_PHONE_TYPE +
        +Theme_InputMethod +
        +Theme_Light_Panel +
        +Theme_NoDisplay +
        +Theme_Panel +
        +thickness +
        +title_bar_tall +
        +topOffset +
        +TYPE_APPLICATION_ATTACHED_DIALOG +
        +TYPE_INPUT_METHOD +
        +TYPE_INPUT_METHOD_DIALOG +
        + +
        U  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +V +W + TOP +

        +UNKNOWN_LENGTH +
        +UPDATE_DEVICE_STATS +
        +updatePeriodMillis +
        + +
        V  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +W + TOP +

        +verticalCorrection +
        +verticalGap +
        +VideoView_error_text_invalid_progressive_playback +
        +voiceLanguage +
        +voiceLanguageModel +
        +voiceMaxResults +
        +voicePromptText +
        +voiceSearchMode +
        +VOLUME_NOTIFICATION +
        + +
        W  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V + TOP +

        +Widget_KeyboardView +
        +WIFI_MAX_DHCP_RETRY_COUNT +
        +WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS +
        +WIFI_MODE_FULL +
        +WIFI_MODE_SCAN_ONLY +
        +WIFI_SLEEP_POLICY +
        +WIFI_SLEEP_POLICY_DEFAULT +
        +WIFI_SLEEP_POLICY_NEVER +
        +WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED +
        +windowDisablePreview +
        +windowNoDisplay +
        +windowSoftInputMode +
        +WRITE_SECURE_SETTINGS +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/fields_index_all.html b/docs/html/sdk/api_diff/3/changes/fields_index_all.html new file mode 100644 index 0000000000000000000000000000000000000000..786a360054524aca002f0729a957e98616760108 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/fields_index_all.html @@ -0,0 +1,1270 @@ + + + + + + + + + +Field Differences Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +Fields +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +ACCELEROMETER_ROTATION +
        +ACTION_AIRPLANE_MODE_SETTINGS +
        +ACTION_APPLICATION_DEVELOPMENT_SETTINGS +
        +ACTION_AUDIO_BECOMING_NOISY +
        +ACTION_BACKGROUND_DATA_SETTING_CHANGED +
        +ACTION_DATA_ROAMING_SETTINGS +
        +ACTION_IMAGE_CAPTURE +
        +ACTION_INPUT_METHOD_CHANGED +
        +ACTION_INPUT_METHOD_SETTINGS +
        +ACTION_INTERNAL_STORAGE_SETTINGS +
        +ACTION_MANAGE_APPLICATIONS_SETTINGS +
        +ACTION_MEDIA_CHECKING +
        +ACTION_MEDIA_NOFS +
        +ACTION_MEMORY_CARD_SETTINGS +
        +ACTION_NETWORK_OPERATOR_SETTINGS +
        +ACTION_OUTSIDE +
        +ACTION_PACKAGE_DATA_CLEARED +
        +ACTION_PACKAGE_REPLACED +
        +ACTION_PHONE_STATE_CHANGED +
        +ACTION_QUICK_LAUNCH_SETTINGS +
        +ACTION_SEARCH_LONG_PRESS +
        +ACTION_SYNC_SETTINGS +
        +ACTION_SYSTEM_TUTORIAL +
        +ACTION_USER_DICTIONARY_SETTINGS +
        +ACTION_USER_PRESENT +
        +ACTION_VIDEO_CAPTURE +
        +ACTION_WIFI_IP_SETTINGS +
        +ADB_ENABLED +
        +addToDictionary +
        +ALIGN_BASELINE +
        +ALIGN_BOTTOM +
        +allowSingleTap +
        +ANDROID_ID +
        +animateOnClick +
        +autoText +
        +AXIS_CLIP +
        +AXIS_MINUS_X +
        +AXIS_MINUS_Y +
        +AXIS_MINUS_Z +
        +AXIS_X +
        +AXIS_Y +
        +AXIS_Z +
        + +
        B  +A +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +backgroundDimEnabled +
        +BIND_APPWIDGET +
        +BIND_INPUT_METHOD +
        +BLUETOOTH_ON +
        +BOOKMARK +
        +bottomOffset +
        +BUCKET_DISPLAY_NAME +
        +BUCKET_ID +
        +BUTTON1 +
        +BUTTON2 +
        +BUTTON3 +
        +BUTTON_NEGATIVE +
        +BUTTON_NEUTRAL +
        +BUTTON_POSITIVE +
        + +
        C  +A +B +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +candidatesArea +
        +candidatesTextStyleSpans +
        +CAP_MODE_CHARACTERS +
        +CAP_MODE_SENTENCES +
        +CAP_MODE_WORDS +
        +capitalize +
        +CATEGORY_GADGET +
        +CATEGORY_INFO +
        +CLIP_HORIZONTAL +
        +CLIP_VERTICAL +
        +closeButton +
        +codes +
        +configPreferences +
        +configure +
        +content +
        +copy +
        +copyUrl +
        +CREATOR
        + in  +android.content.res.AssetFileDescriptor +
        + in  +android.graphics.RectF +
        +cut +
        + +
        D  +A +B +C +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +dark_header +
        +DATA_ROAMING +
        +DATA_X +
        +DATA_Y +
        +DATA_Z +
        +DEBUG_ENABLE_ASSERT +
        +DEBUG_ENABLE_CHECKJNI +
        +DEBUG_ENABLE_DEBUGGER +
        +DEFAULT_SORT_ORDER
        + in  +android.provider.MediaStore.Images.Media +
        + in  +android.provider.MediaStore.Video +
        +DEVICE_PROVISIONED +
        +dialog_alert_title +
        +DISPLAY +
        +DISPLAY_CLIP_HORIZONTAL +
        +DISPLAY_CLIP_VERTICAL +
        +dropDownAnchor +
        +dropDownWidth +
        + +
        E  +A +B +C +D +F +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +editable +
        +editorExtras +
        +enabled +
        +EXTRA_APPLICATION_ID +
        +EXTRA_CREATE_DESCRIPTION +
        +EXTRA_DATA_REMOVED +
        +EXTRA_FINISH_ON_COMPLETION +
        +EXTRA_FORCE_CREATE +
        +EXTRA_INCOMING_NUMBER +
        +EXTRA_MAX_BYTES +
        +EXTRA_MEDIA_ALBUM +
        +EXTRA_MEDIA_ARTIST +
        +EXTRA_MEDIA_FOCUS +
        +EXTRA_MEDIA_TITLE +
        +EXTRA_OUTPUT +
        +EXTRA_REPLACING +
        +EXTRA_SCREEN_ORIENTATION +
        +EXTRA_STATE +
        +EXTRA_STATE_IDLE +
        +EXTRA_STATE_OFFHOOK +
        +EXTRA_STATE_RINGING +
        +EXTRA_VIDEO_QUALITY +
        +extractArea +
        + +
        F  +A +B +C +D +E +G +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +fastScrollEnabled +
        +fillEnabled +
        +FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET +
        +FLAG_ACTIVITY_NO_USER_ACTION +
        +FLAG_ACTIVITY_REORDER_TO_FRONT +
        +FLAG_ALT_FOCUSABLE_IM +
        +FLAG_EDITOR_ACTION +
        +FLAG_FROM_SYSTEM +
        +FLAG_KEEP_TOUCH_MODE +
        +FLAG_NO_HISTORY +
        +FLAG_SOFT_KEYBOARD +
        +FLAG_UPDATE_CURRENT +
        +FLAG_WATCH_OUTSIDE_TOUCH +
        +footerDividersEnabled +
        +FORMAT_JAPAN +
        +FX_KEYPRESS_DELETE +
        +FX_KEYPRESS_RETURN +
        +FX_KEYPRESS_SPACEBAR +
        +FX_KEYPRESS_STANDARD +
        + +
        G  +A +B +C +D +E +F +H +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +GET_CONFIGURATIONS +
        +GET_UNINSTALLED_PACKAGES +
        + +
        H  +A +B +C +D +E +F +G +I +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +handle +
        +HAPTIC_FEEDBACK_ENABLED
        + in  +android.provider.Settings.System +
        + in  +android.view.View +
        +hapticFeedbackEnabled +
        +hardKeyboardHidden +
        +HARDKEYBOARDHIDDEN_NO +
        +HARDKEYBOARDHIDDEN_UNDEFINED +
        +HARDKEYBOARDHIDDEN_YES +
        +headerDividersEnabled +
        +horizontalGap +
        +HTTP_PROXY +
        + +
        I  +A +B +C +D +E +F +G +H +K +L +M +N +P +R +S +T +U +V +W + TOP +

        +ic_btn_speak_now +
        +iconPreview +
        +imeActionId +
        +imeActionLabel +
        +imeExtractEnterAnimation +
        +imeExtractExitAnimation +
        +imeFullscreenBackground +
        +imeOptions +
        +initialLayout +
        +innerRadius +
        +INPUT_METHOD_FROM_FOCUSABLE +
        +INPUT_METHOD_NEEDED +
        +INPUT_METHOD_NOT_NEEDED +
        +INPUT_METHOD_SERVICE +
        +inputArea +
        +inputExtractEditText +
        +inputMethod +
        +inputType +
        +INSTALL_FAILED_CONFLICTING_PROVIDER +
        +INSTALL_NON_MARKET_APPS +
        +INTENT_ACTION_MEDIA_SEARCH +
        +INTENT_ACTION_STILL_IMAGE_CAMERA +
        +INTENT_ACTION_VIDEO_CAMERA +
        +INTERVAL_DAY +
        +INTERVAL_FIFTEEN_MINUTES +
        +INTERVAL_HALF_DAY +
        +INTERVAL_HALF_HOUR +
        +INTERVAL_HOUR +
        +isDefault +
        +isModifier +
        +isRepeatable +
        +isScrollContainer +
        +isSticky +
        + +
        K  +A +B +C +D +E +F +G +H +I +L +M +N +P +R +S +T +U +V +W + TOP +

        +KEY_LOCATION_CHANGED +
        +KEY_PROVIDER_ENABLED +
        +KEY_STATUS_CHANGED +
        +keyBackground +
        +keyboardMode +
        +keyboardView +
        +KEYCODE_MEDIA_FAST_FORWARD +
        +KEYCODE_MEDIA_NEXT +
        +KEYCODE_MEDIA_PLAY_PAUSE +
        +KEYCODE_MEDIA_PREVIOUS +
        +KEYCODE_MEDIA_REWIND +
        +KEYCODE_MEDIA_STOP +
        +KEYCODE_MUTE +
        +keyEdgeFlags +
        +keyHeight +
        +keyIcon +
        +keyLabel +
        +keyOutputText +
        +keyPreviewHeight +
        +keyPreviewLayout +
        +keyPreviewOffset +
        +keyTextColor +
        +keyTextSize +
        +keyWidth +
        + +
        L  +A +B +C +D +E +F +G +H +I +K +M +N +P +R +S +T +U +V +W + TOP +

        +labelTextSize +
        +LIGHT_NO_MOON +
        +LOCATION_PROVIDERS_ALLOWED +
        +LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED +
        +LOGGING_ID +
        + +
        M  +A +B +C +D +E +F +G +H +I +K +L +N +P +R +S +T +U +V +W + TOP +

        +MAX_KEYCODE +
        +MEDIA_CHECKING +
        +MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK +
        +MEDIA_INFO_BAD_INTERLEAVING +
        +MEDIA_INFO_NOT_SEEKABLE +
        +MEDIA_INFO_UNKNOWN +
        +MEDIA_INFO_VIDEO_TRACK_LAGGING +
        +MEDIA_NOFS +
        +MEDIA_RECORDER_ERROR_UNKNOWN +
        +MEDIA_RECORDER_INFO_MAX_DURATION_REACHED +
        +MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED +
        +MEDIA_RECORDER_INFO_UNKNOWN +
        +MODE_APPEND +
        +MOUNT_FORMAT_FILESYSTEMS +
        +mVerticalAlignment +
        + +
        N  +A +B +C +D +E +F +G +H +I +K +L +M +P +R +S +T +U +V +W + TOP +

        +NETWORK_PREFERENCE +
        +noHistory +
        +NUM_STREAMS +
        +NUMBER_OF_SONGS_FOR_ARTIST +
        +numeric +
        + +
        P  +A +B +C +D +E +F +G +H +I +K +L +M +N +R +S +T +U +V +W + TOP +

        +PARENTAL_CONTROL_ENABLED +
        +PARENTAL_CONTROL_LAST_UPDATE +
        +PARENTAL_CONTROL_REDIRECT_URL +
        +password +
        +paste +
        +phoneNumber +
        +PHONETIC_NAME
        + in  +android.provider.Contacts.Intents.Insert +
        + in  +android.provider.Contacts.PeopleColumns +
        +popupCharacters +
        +popupKeyboard +
        +popupLayout +
        +privateImeOptions +
        + +
        R  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +S +T +U +V +W + TOP +

        +RAW_AMR +
        +RAW_DATA_INDEX +
        +RAW_DATA_X +
        +RAW_DATA_Y +
        +RAW_DATA_Z +
        +reqFiveWayNav +
        +reqHardKeyboard +
        +reqKeyboardType +
        +reqNavigation +
        +reqTouchScreen +
        +ROUTE_BLUETOOTH +
        +ROUTE_BLUETOOTH_A2DP +
        +ROUTE_BLUETOOTH_SCO +
        +rowEdgeFlags +
        + +
        S  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +T +U +V +W + TOP +

        +SCREEN_BRIGHTNESS_CHANGED +
        +SCREEN_ORIENTATION_CHANGED +
        +screenBrightness +
        +screenOrientation +
        +searchButtonText +
        +SECONDARY_EMAIL +
        +SECONDARY_EMAIL_TYPE +
        +SECONDARY_PHONE +
        +SECONDARY_PHONE_TYPE +
        +selectAll +
        +SENSOR_ACCELEROMETER +
        +SENSOR_ALL +
        +SENSOR_LIGHT +
        +SENSOR_MAGNETIC_FIELD +
        +SENSOR_MAX +
        +SENSOR_MIN +
        +SENSOR_ORIENTATION +
        +SENSOR_ORIENTATION_RAW +
        +SENSOR_PROXIMITY +
        +SENSOR_TEMPERATURE +
        +SENSOR_TRICORDER +
        +SETTINGS_CLASSNAME +
        +settingsActivity +
        +sharedUserId +
        +sharedUserLabel
        + in  +android.R.attr +
        + in  +android.content.pm.PackageInfo +
        +SHOW_OR_CREATE_CONTACT +
        +singleLine +
        +smoothScrollbar +
        +SOFT_INPUT_ADJUST_PAN +
        +SOFT_INPUT_ADJUST_RESIZE +
        +SOFT_INPUT_ADJUST_UNSPECIFIED +
        +SOFT_INPUT_IS_FORWARD_NAVIGATION +
        +SOFT_INPUT_MASK_ADJUST +
        +SOFT_INPUT_MASK_STATE +
        +SOFT_INPUT_MODE_CHANGED +
        +SOFT_INPUT_STATE_ALWAYS_HIDDEN +
        +SOFT_INPUT_STATE_ALWAYS_VISIBLE +
        +SOFT_INPUT_STATE_HIDDEN +
        +SOFT_INPUT_STATE_UNCHANGED +
        +SOFT_INPUT_STATE_UNSPECIFIED +
        +SOFT_INPUT_STATE_VISIBLE +
        +softInputMode
        + in  +android.content.pm.ActivityInfo +
        + in  +android.view.WindowManager.LayoutParams +
        +SPAN_COMPOSING +
        +SPAN_INTERMEDIATE +
        +SPAN_POINT_MARK_MASK +
        +startSelectingText +
        +state_long_pressable +
        +stopSelectingText +
        +STREAM_NOTIFICATION +
        +STRETCH_SPACING_UNIFORM +
        +switchInputMethod +
        + +
        T  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +U +V +W + TOP +

        +TERTIARY_EMAIL +
        +TERTIARY_EMAIL_TYPE +
        +TERTIARY_PHONE +
        +TERTIARY_PHONE_TYPE +
        +Theme_InputMethod +
        +Theme_Light_Panel +
        +Theme_NoDisplay +
        +Theme_Panel +
        +thickness +
        +title_bar_tall +
        +topOffset +
        +TYPE_APPLICATION_ATTACHED_DIALOG +
        +TYPE_INPUT_METHOD +
        +TYPE_INPUT_METHOD_DIALOG +
        + +
        U  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +V +W + TOP +

        +UNKNOWN_LENGTH +
        +UPDATE_DEVICE_STATS +
        +updatePeriodMillis +
        +USB_MASS_STORAGE_ENABLED +
        +USE_GOOGLE_MAIL +
        + +
        V  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +W + TOP +

        +verticalCorrection +
        +verticalGap +
        +VideoView_error_text_invalid_progressive_playback +
        +voiceLanguage +
        +voiceLanguageModel +
        +voiceMaxResults +
        +voicePromptText +
        +voiceSearchMode +
        +VOLUME_NOTIFICATION +
        + +
        W  +A +B +C +D +E +F +G +H +I +K +L +M +N +P +R +S +T +U +V + TOP +

        +Widget_KeyboardView +
        +WIFI_MAX_DHCP_RETRY_COUNT +
        +WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS +
        +WIFI_MODE_FULL +
        +WIFI_MODE_SCAN_ONLY +
        +WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON +
        +WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY +
        +WIFI_NUM_OPEN_NETWORKS_KEPT +
        +WIFI_ON +
        +WIFI_SLEEP_POLICY +
        +WIFI_SLEEP_POLICY_DEFAULT +
        +WIFI_SLEEP_POLICY_NEVER +
        +WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED +
        +WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE +
        +WIFI_WATCHDOG_AP_COUNT +
        +WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS +
        +WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED +
        +WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS +
        +WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT +
        +WIFI_WATCHDOG_MAX_AP_CHECKS +
        +WIFI_WATCHDOG_ON +
        +WIFI_WATCHDOG_PING_COUNT +
        +WIFI_WATCHDOG_PING_DELAY_MS +
        +WIFI_WATCHDOG_PING_TIMEOUT_MS +
        +windowDisablePreview +
        +windowNoDisplay +
        +windowSoftInputMode +
        +WRITE_SECURE_SETTINGS +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/fields_index_changes.html b/docs/html/sdk/api_diff/3/changes/fields_index_changes.html new file mode 100644 index 0000000000000000000000000000000000000000..3f5dd5a9b77523c99c20ea0fcb332c0917c25bf7 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/fields_index_changes.html @@ -0,0 +1,471 @@ + + + + + + + + + +Field Changes Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Fields +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +C +D +E +H +I +L +M +N +P +R +S +U +W + TOP +

        +ADB_ENABLED +
        +ANDROID_ID +
        +autoText +
        + +
        B  +A +C +D +E +H +I +L +M +N +P +R +S +U +W + TOP +

        +BLUETOOTH_ON +
        +BUTTON1 +
        +BUTTON2 +
        +BUTTON3 +
        + +
        C  +A +B +D +E +H +I +L +M +N +P +R +S +U +W + TOP +

        +capitalize +
        + +
        D  +A +B +C +E +H +I +L +M +N +P +R +S +U +W + TOP +

        +DATA_ROAMING +
        +DATA_X +
        +DATA_Y +
        +DATA_Z +
        +DEFAULT_SORT_ORDER
        + in  +android.provider.MediaStore.Images.Media +
        + in  +android.provider.MediaStore.Video +
        +DEVICE_PROVISIONED +
        + +
        E  +A +B +C +D +H +I +L +M +N +P +R +S +U +W + TOP +

        +editable +
        +enabled +
        + +
        H  +A +B +C +D +E +I +L +M +N +P +R +S +U +W + TOP +

        +HTTP_PROXY +
        + +
        I  +A +B +C +D +E +H +L +M +N +P +R +S +U +W + TOP +

        +inputMethod +
        +INSTALL_NON_MARKET_APPS +
        + +
        L  +A +B +C +D +E +H +I +M +N +P +R +S +U +W + TOP +

        +LIGHT_NO_MOON +
        +LOCATION_PROVIDERS_ALLOWED +
        +LOGGING_ID +
        + +
        M  +A +B +C +D +E +H +I +L +N +P +R +S +U +W + TOP +

        +MAX_KEYCODE +
        + +
        N  +A +B +C +D +E +H +I +L +M +P +R +S +U +W + TOP +

        +NETWORK_PREFERENCE +
        +NUM_STREAMS +
        +numeric +
        + +
        P  +A +B +C +D +E +H +I +L +M +N +R +S +U +W + TOP +

        +PARENTAL_CONTROL_ENABLED +
        +PARENTAL_CONTROL_LAST_UPDATE +
        +PARENTAL_CONTROL_REDIRECT_URL +
        +password +
        +phoneNumber +
        + +
        R  +A +B +C +D +E +H +I +L +M +N +P +S +U +W + TOP +

        +RAW_DATA_INDEX +
        +RAW_DATA_X +
        +RAW_DATA_Y +
        +RAW_DATA_Z +
        +ROUTE_BLUETOOTH +
        + +
        S  +A +B +C +D +E +H +I +L +M +N +P +R +U +W + TOP +

        +searchButtonText +
        +SENSOR_ACCELEROMETER +
        +SENSOR_ALL +
        +SENSOR_LIGHT +
        +SENSOR_MAGNETIC_FIELD +
        +SENSOR_MAX +
        +SENSOR_MIN +
        +SENSOR_ORIENTATION +
        +SENSOR_ORIENTATION_RAW +
        +SENSOR_PROXIMITY +
        +SENSOR_TEMPERATURE +
        +SENSOR_TRICORDER +
        +SETTINGS_CLASSNAME +
        +singleLine +
        + +
        U  +A +B +C +D +E +H +I +L +M +N +P +R +S +W + TOP +

        +USB_MASS_STORAGE_ENABLED +
        +USE_GOOGLE_MAIL +
        + +
        W  +A +B +C +D +E +H +I +L +M +N +P +R +S +U + TOP +

        +WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON +
        +WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY +
        +WIFI_NUM_OPEN_NETWORKS_KEPT +
        +WIFI_ON +
        +WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE +
        +WIFI_WATCHDOG_AP_COUNT +
        +WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS +
        +WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED +
        +WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS +
        +WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT +
        +WIFI_WATCHDOG_MAX_AP_CHECKS +
        +WIFI_WATCHDOG_ON +
        +WIFI_WATCHDOG_PING_COUNT +
        +WIFI_WATCHDOG_PING_DELAY_MS +
        +WIFI_WATCHDOG_PING_TIMEOUT_MS +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/fields_index_removals.html b/docs/html/sdk/api_diff/3/changes/fields_index_removals.html new file mode 100644 index 0000000000000000000000000000000000000000..58ad6557e1ebcbc5481b522933fc35c9cbec676e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/fields_index_removals.html @@ -0,0 +1,68 @@ + + + + + + + + + +Field Removals Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Fields +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        C  + TOP +

        +CATEGORY_GADGET +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.lang.Character.UnicodeBlock.html b/docs/html/sdk/api_diff/3/changes/java.lang.Character.UnicodeBlock.html new file mode 100644 index 0000000000000000000000000000000000000000..f7c9d8f64068f1d6013d71581a75d639ce64b189 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.lang.Character.UnicodeBlock.html @@ -0,0 +1,126 @@ + + + + + + + + + +java.lang.Character.UnicodeBlock + + + + + + + + + + +
        +
        +
        +

        +Class java.lang.Character.UnicodeBlock +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + UnicodeBlock forName(String) + +Change from non-final to final.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.lang.Class.html b/docs/html/sdk/api_diff/3/changes/java.lang.Class.html new file mode 100644 index 0000000000000000000000000000000000000000..fa0b0563995258fcb8410c2f1b6fbf9587f59ad9 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.lang.Class.html @@ -0,0 +1,166 @@ + + + + + + + + + +java.lang.Class + + + + + + + + + + +
        +
        +
        +

        +Class java.lang.Class +

        + + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Methods +
        + + Class[] getClasses() + +Change in return type from Class<?> to Class[].
        +
         
        + + Constructor[] getConstructors() + +Change in return type from Constructor<T> to Constructor[].
        +
         
        + + Class[] getDeclaredClasses() + +Change in return type from Class<?> to Class[].
        +
         
        + + Constructor[] getDeclaredConstructors() + +Change in return type from Constructor<T> to Constructor[].
        +
         
        + + Class[] getInterfaces() + +Change in return type from Class<?> to Class[].
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.lang.String.html b/docs/html/sdk/api_diff/3/changes/java.lang.String.html new file mode 100644 index 0000000000000000000000000000000000000000..5c41b8cc893e57213bbed02a95d320c5002863ec --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.lang.String.html @@ -0,0 +1,161 @@ + + + + + + + + + +java.lang.String + + + + + + + + + + +
        +
        +
        +

        +Class java.lang.String +

        + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Constructors +
        + + String() + +  
        + + String(byte[]) + +  
        + + String(byte[], int) + +  
        + + String(byte[], int, int) + +  
        + + String(byte[], int, int, int) + +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.lang.reflect.Proxy.html b/docs/html/sdk/api_diff/3/changes/java.lang.reflect.Proxy.html new file mode 100644 index 0000000000000000000000000000000000000000..f593c0ee8e7304725fe06d031fba2a2ce7f501fb --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.lang.reflect.Proxy.html @@ -0,0 +1,126 @@ + + + + + + + + + +java.lang.reflect.Proxy + + + + + + + + + + +
        +
        +
        +

        +Class java.lang.reflect.Proxy +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + Class<?> getProxyClass(ClassLoader, Class<?>) + +Change in signature from (ClassLoader, ) to (ClassLoader, Class<?>).
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.net.Socket.html b/docs/html/sdk/api_diff/3/changes/java.net.Socket.html new file mode 100644 index 0000000000000000000000000000000000000000..6027217d619c2a0cf04a7bcada2f3d4d0ec9fe41 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.net.Socket.html @@ -0,0 +1,161 @@ + + + + + + + + + +java.net.Socket + + + + + + + + + + +
        +
        +
        +

        +Class java.net.Socket +

        + +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Constructors +
        + + Socket() + +  
        + + Socket(String, int) + +  
        + + Socket(String, int, InetAddress, int) + +  
        + + Socket(Proxy) + +  
        + + Socket(SocketImpl) + +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.util.Date.html b/docs/html/sdk/api_diff/3/changes/java.util.Date.html new file mode 100644 index 0000000000000000000000000000000000000000..6a8dd268563568aeb719425fc4b2b78af47f2e11 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.util.Date.html @@ -0,0 +1,134 @@ + + + + + + + + + +java.util.Date + + + + + + + + + + +
        +
        +
        +

        +Class java.util.Date +

        + +

        + + + + + + + + + + + + + + +
        Changed Constructors +
        + + Date() + +  
        + + Date(int, int, int, int, int, int) + +  
        +  + + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.util.jar.Pack200.Packer.html b/docs/html/sdk/api_diff/3/changes/java.util.jar.Pack200.Packer.html new file mode 100644 index 0000000000000000000000000000000000000000..75b4cbc4a8f8efa329d505ca215768fd9309ba74 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.util.jar.Pack200.Packer.html @@ -0,0 +1,130 @@ + + + + + + + + + +java.util.jar.Pack200.Packer + + + + + + + + + + +
        +
        +
        +

        +Interface java.util.jar.Pack200.Packer +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + void addPropertyChangeListener(PropertyChangeListener) +  
        + + void removePropertyChangeListener(PropertyChangeListener) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.util.jar.Pack200.Unpacker.html b/docs/html/sdk/api_diff/3/changes/java.util.jar.Pack200.Unpacker.html new file mode 100644 index 0000000000000000000000000000000000000000..382fdea8428e97f848b1c71e31f3975556a49df3 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.util.jar.Pack200.Unpacker.html @@ -0,0 +1,130 @@ + + + + + + + + + +java.util.jar.Pack200.Unpacker + + + + + + + + + + +
        +
        +
        +

        +Interface java.util.jar.Pack200.Unpacker +

        + + +

        + + + + + + + + + + + + +
        Added Methods +
        + + void addPropertyChangeListener(PropertyChangeListener) +  
        + + void removePropertyChangeListener(PropertyChangeListener) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.util.logging.Level.html b/docs/html/sdk/api_diff/3/changes/java.util.logging.Level.html new file mode 100644 index 0000000000000000000000000000000000000000..7f5fd19782c8b7571f2b0f934233155fbf5f8343 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.util.logging.Level.html @@ -0,0 +1,127 @@ + + + + + + + + + +java.util.logging.Level + + + + + + + + + + +
        +
        +
        +

        +Class java.util.logging.Level +

        + + +

        + + + + + + + + + +
        Changed Methods +
        + + Level parse(String) + +Change in exceptions thrown from no exceptions to java.lang.IllegalArgumentException.
        + Change from final to non-final.
        +
         
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/java.util.logging.LogManager.html b/docs/html/sdk/api_diff/3/changes/java.util.logging.LogManager.html new file mode 100644 index 0000000000000000000000000000000000000000..d259077f26d999fe9281fad8a14a0e38814fd3ff --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/java.util.logging.LogManager.html @@ -0,0 +1,137 @@ + + + + + + + + + +java.util.logging.LogManager + + + + + + + + + + +
        +
        +
        +

        +Class java.util.logging.LogManager +

        + + +

        + + + + + + + + + + + + + + + + +
        Added Methods +
        + + void addPropertyChangeListener(PropertyChangeListener) +  
        + + LoggingMXBean getLoggingMXBean() +  
        + + void removePropertyChangeListener(PropertyChangeListener) +  
        +  + +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/jdiff_help.html b/docs/html/sdk/api_diff/3/changes/jdiff_help.html new file mode 100644 index 0000000000000000000000000000000000000000..21a59f92d5261b54f562de26ad1c5b809341ff4e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/jdiff_help.html @@ -0,0 +1,135 @@ + + + + + + + + + +JDiff Help + + + + + + + + + + + + + + + + + +
        Generated by
        JDiff
        +
        + +
        +

        JDiff Documentation

        +
        +
        +JDiff is a Javadoc doclet which generates a report of the API differences between two versions of a product. It does not report changes in Javadoc comments, or changes in what a class or method does. +This help page describes the different parts of the output from JDiff. +
        +
        + See the reference page in the source for JDiff for information about how to generate a report like this one. +
        +
        +The indexes shown in the top-left frame help show each type of change in more detail. The index "All Differences" contains all the differences between the APIs, in alphabetical order. +These indexes all use the same format: +
          +
        • Removed packages, classes, constructors, methods and fields are struck through.
        • +
        • Added packages, classes, constructors, methods and fields appear in bold.
        • +
        • Changed packages, classes, constructors, methods and fields appear in normal text.
        • +
        +
        +
        +You can always tell when you are reading a JDiff page, rather than a Javadoc page, by the color of the index bar and the color of the background. +Links which take you to a Javadoc page are always in a typewriter font. +Just like Javadoc, all interface names are in italic, and class names are not italicized. Where there are multiple entries in an index with the same name, the heading for them is also in italics, but is not a link. +
        +
        +

        Javadoc

        +This is a link to the top-level Javadoc page for the new version of the product. +
        +
        +

        Overview

        +The overview is the top-level summary of what was removed, added and changed between versions. +
        +
        +

        Package

        +This is a link to the package containing the current changed class or interface. +
        +
        +

        Class

        +This is highlighted when you are looking at the changed class or interface. +
        +
        +

        Text Changes

        +This is a link to the top-level index of all documentation changes for the current package or class. +If it is not present, then there are no documentation changes for the current package or class. +This link can be removed entirely by not using the -docchanges option. +
        +
        +

        Statistics

        +This is a link to a page which shows statistics about the changes between the two APIs. +This link can be removed entirely by not using the -stats option. +
        +
        +

        Help

        +A link to this Help page for JDiff. +
        +
        +

        Prev/Next

        +These links take you to the previous and next changed package or class. +
        +
        +

        Frames/No Frames

        +These links show and hide the HTML frames. All pages are available with or without frames. +
        +
        +

        Complex Changes

        +There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. +In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/jdiff_statistics.html b/docs/html/sdk/api_diff/3/changes/jdiff_statistics.html new file mode 100644 index 0000000000000000000000000000000000000000..6faea52ee8f0d6fe9be23e119a763ce591c1cebb --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/jdiff_statistics.html @@ -0,0 +1,1284 @@ + + + + + + + + + +API Change Statistics + + + + + + + + + + +
        +
        +
        +

        API Change Statistics

        +

        +The percent change statistic reported for all elements in the "to" API Level specification is defined recursively as follows:

        +
        +Percentage difference = 100 * (added + removed + 2*changed)
        +                        -----------------------------------
        +                        sum of public elements in BOTH APIs
        +
        +

        where added is the number of packages added, removed is the number of packages removed, and changed is the number of packages changed. +This definition is applied recursively for the classes and their program elements, so the value for a changed package will be less than 1, unless every class in that package has changed. +The definition ensures that if all packages are removed and all new packages are +added, the change will be 100%. Values are rounded here, so a value of 0% indicates a percentage difference of less than 0.5%.

        +

        The overall difference between the two APIs is approximately 4%. +

        +

        Contents

        +
        Changed Packages
        Sorted by percentage difference
        +
        Changed Classes and Interfaces
        Sorted by percentage difference
        +
        Total of Differences
        Listed by number and type
        +
        + +

        Changed Packages, Sorted by Percentage Difference

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Percentage DifferencePackage
        33android.opengl
        27android.media
        24android.text.style
        22android.hardware
        22android.location
        13android.content.res
        12dalvik.system
        9android.telephony
        9android.text.method
        8android.app
        8android.test
        8android.test.suitebuilder
        7android
        7android.text
        6android.provider
        6android.view
        5android.widget
        5android.os
        4android.webkit
        3android.content.pm
        2android.util
        1android.content
        1java.util.jar
        1android.graphics.drawable.shapes
        <1android.net
        <1android.graphics.drawable
        <1java.util.logging
        <1android.test.mock
        <1java.lang.reflect
        <1android.view.animation
        <1android.net.wifi
        <1android.telephony.gsm
        <1java.net
        <1android.database
        <1android.graphics
        <1java.lang
        <1android.database.sqlite
        <1android.preference
        <1java.util
        +
        + +

        Changed Classes and Interfaces, Sorted by Percentage Difference

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Percentage
        Difference
        Class or Interface
        84 +android.test.TouchUtils
        81 +dalvik.system.Zygote
        66 +android.webkit.UrlInterceptHandler
        61 +android.provider.MediaStore
        53 +android.view.GestureDetector
        50 +android.app.LauncherActivity
        50 +android.text.style.AlignmentSpan.Standard
        50 +android.text.style.StrikethroughSpan
        50 +android.text.style.UnderlineSpan
        50 +android.widget.PopupWindow.OnDismissListener
        48 +android.app.AlertDialog
        46 +android.content.DialogInterface
        45 +android.view.ViewConfiguration
        42 +android.text.method.KeyListener
        40 +android.text.Annotation
        40 +android.text.style.BackgroundColorSpan
        40 +android.text.style.ForegroundColorSpan
        40 +android.text.style.SubscriptSpan
        40 +android.text.style.SuperscriptSpan
        40 +android.text.style.URLSpan
        39 +android.media.MediaRecorder
        38 +android.text.style.DynamicDrawableSpan
        36 +android.content.res.AssetFileDescriptor
        36 +android.location.LocationManager
        34 +android.hardware.SensorManager
        33 +android.text.AutoText
        33 +android.text.method.Touch
        33 +android.text.style.AbsoluteSizeSpan
        33 +android.text.style.LeadingMarginSpan.Standard
        33 +android.text.style.RelativeSizeSpan
        33 +android.text.style.ScaleXSpan
        33 +android.text.style.StyleSpan
        33 +android.text.style.TypefaceSpan
        33 +android.widget.RemoteViews.ActionException
        31 +android.widget.RemoteViews
        30 +android.provider.Settings
        28 +android.text.style.QuoteSpan
        27 +android.app.AlarmManager
        26 +android.text.style.ImageSpan
        25 +android.hardware.SensorListener
        25 +android.text.method.MetaKeyKeyListener
        25 +android.text.style.BulletSpan
        25 +android.widget.ResourceCursorAdapter
        23 +android.provider.Contacts.Intents
        21 +android.widget.PopupWindow
        20 +android.R.id
        20 +android.provider.Settings.System
        20 +android.app.ActivityManager
        20 +android.text.method.BaseKeyListener
        20 +android.util.TimeUtils
        20 +android.widget.AutoCompleteTextView
        19 +android.provider.Contacts.Intents.Insert
        17 +android.view.GestureDetector.SimpleOnGestureListener
        16 +android.provider.MediaStore.Video
        16 +android.text.SpanWatcher
        16 +android.text.TextWatcher
        16 +android.text.style.ClickableSpan
        16 +android.text.style.MaskFilterSpan
        16 +android.text.style.RasterizerSpan
        16 +android.text.style.TextAppearanceSpan
        15 +android.webkit.UrlInterceptRegistry
        14 +android.media.MediaRecorder.OutputFormat
        14 +android.net.NetworkInfo
        14 +android.test.suitebuilder.TestMethod
        14 +android.text.method.QwertyKeyListener
        14 +android.widget.AbsSeekBar
        12 +android.view.WindowManager.LayoutParams
        12 +android.test.ActivityInstrumentationTestCase
        12 +android.test.InstrumentationTestCase
        12 +android.widget.AbsoluteLayout
        12 +java.util.logging.LogManager
        11 +android.view.Gravity
        11 +android.widget.CursorAdapter
        11 +android.widget.TextView
        11 +android.text.method.DateKeyListener
        11 +android.text.method.DateTimeKeyListener
        11 +android.text.method.DialerKeyListener
        11 +android.text.method.TimeKeyListener
        11 +android.webkit.WebHistoryItem
        11 +java.util.jar.Pack200.Unpacker
        10 +android.media.MediaPlayer
        10 +android.provider.MediaStore.Video.VideoColumns
        10 +android.test.ProviderTestCase
        10 +android.test.suitebuilder.TestSuiteBuilder
        10 +android.widget.Chronometer
        10 +java.net.Socket
        9 +android.graphics.drawable.TransitionDrawable
        9 +android.text.method.MultiTapKeyListener
        8 +android.media.AudioManager
        8 +android.view.ViewTreeObserver
        8 +java.lang.reflect.Proxy
        8 +android.content.pm.PackageInfo
        7 +android.text.Spanned
        7 +android.text.method.DigitsKeyListener
        7 +android.hardware.Camera
        7 +android.R.attr
        7 +android.telephony.TelephonyManager
        7 +android.media.SoundPool
        7 +android.os.Environment
        6 +android.view.KeyEvent
        6 +java.lang.String
        6 +android.graphics.drawable.shapes.Shape
        6 +android.text.method.MovementMethod
        6 +android.view.OrientationListener
        6 +dalvik.system.DexFile
        6 +java.util.Date
        6 +android.text.TextUtils
        6 +android.os.ParcelFileDescriptor
        5 +android.webkit.WebView
        5 +android.graphics.drawable.RotateDrawable
        5 +android.graphics.drawable.ScaleDrawable
        5 +android.provider.MediaStore.Audio.AlbumColumns
        5 +android.provider.MediaStore.Audio.Media
        5 +android.webkit.WebSettings
        5 +android.content.res.Resources
        5 +android.graphics.RectF
        5 +android.os.Looper
        5 +android.provider.Contacts.PeopleColumns
        5 +android.text.method.ArrowKeyMovementMethod
        5 +android.text.method.TextKeyListener
        5 +android.view.ViewDebug
        5 +android.widget.Scroller
        5 +android.widget.AbsListView
        5 +android.net.ConnectivityManager
        5 +android.view.KeyCharacterMap
        4 +android.content.res.Configuration
        4 +android.widget.ProgressBar
        4 +android.widget.SimpleCursorAdapter
        4 +android.R.string
        4 +java.lang.Class
        4 +java.util.jar.Pack200.Packer
        4 +android.provider.MediaStore.Images.Media
        3 +android.os.Build
        3 +android.os.IBinder
        3 +android.text.method.ScrollingMovementMethod
        3 +android.util.SparseIntArray
        3 +android.content.Intent
        3 +android.content.ContentResolver
        3 +android.net.wifi.WifiManager
        3 +android.content.BroadcastReceiver
        3 +android.os.Handler
        3 +android.view.Menu
        3 +android.view.animation.Animation
        3 +android.view.animation.Transformation
        2 +android.webkit.URLUtil
        2 +java.util.logging.Level
        2 +android.R.style
        2 +android.os.Binder
        2 +android.view.ViewParent
        2 +android.widget.GridView
        2 +android.test.mock.MockPackageManager
        2 +android.view.View
        2 +android.widget.ListView
        2 +android.app.PendingIntent
        2 +android.content.pm.PackageManager
        2 +android.telephony.PhoneNumberUtils
        2 +android.content.ContentProvider
        2 +android.Manifest.permission
        2 +android.widget.ArrayAdapter
        2 +android.content.pm.ActivityInfo
        2 +dalvik.system.VMDebug
        1 +android.database.sqlite.SQLiteDatabase
        1 +android.content.res.TypedArray
        1 +android.app.Activity
        1 +android.preference.DialogPreference
        1 +android.view.Window
        1 +android.graphics.Bitmap
        1 +android.os.Debug
        1 +android.provider.Browser
        1 +android.os.Parcel
        1 +android.database.DatabaseUtils
        1 +android.media.RingtoneManager
        1 +android.graphics.Rect
        1 +android.telephony.gsm.SmsMessage
        1 +android.database.Cursor
        1 +android.database.CursorWrapper
        1 +android.view.MotionEvent
        1 +android.location.Location
        1 +android.graphics.drawable.Drawable
        <1 +android.R.drawable
        <1 +android.app.Instrumentation
        <1 +android.graphics.Canvas
        <1 +android.content.Context
        <1 +android.view.ViewGroup
        <1 +java.lang.Character.UnicodeBlock
        <1 +android.text.style.UpdateLayout
        +
        + +

        Total of Differences, by Number and Type

        +

        +The table below lists the numbers of program elements (packages, classes, constructors, methods, and fields) that were removed, added or changed. The table includes only the highest-level program elements — that is, if a class with two methods was added, the number of methods added does not include those two methods, but the number of classes added does include that class. +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + Number of Differences
          + RemovalsAdditionsChangesTotal
        Packages063945
        Classes and Interfaces067186253
        Constructors1361552
        Methods038171452
        Fields129668365
        Total27863791167
        +
        + +
        +
        + + + diff --git a/docs/html/sdk/api_diff/3/changes/jdiff_topleftframe.html b/docs/html/sdk/api_diff/3/changes/jdiff_topleftframe.html new file mode 100644 index 0000000000000000000000000000000000000000..666c9dd3ca8dc8ca610d25e76f98dd05b9798fac --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/jdiff_topleftframe.html @@ -0,0 +1,64 @@ + + + + + + + + + +Android API Version Differences + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + Select a Diffs Index:
        All Differences
        By Package
        By Class
        By Constructor
        By Method
        By Field
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/methods_index_additions.html b/docs/html/sdk/api_diff/3/changes/methods_index_additions.html new file mode 100644 index 0000000000000000000000000000000000000000..1fa2bdb6c70628c89af348ff38ddd5825d052086 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/methods_index_additions.html @@ -0,0 +1,1397 @@ + + + + + + + + + +Method Additions Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Methods +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +addGpsStatusListener +(Listener)
        +addOnScrollChangedListener +(OnScrollChangedListener)
        +addPropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        +addTestProvider +(String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int)
        +adjustMetaAfterKeypress +(long)
        +applyDisplay +(int, Rect, Rect)
        + +
        B  +A +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +beginBatchEdit +()
        +bringPointIntoView +(int)
        + +
        C  +A +B +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +calculateLength +(CharSequence, boolean)
        +callActivityOnUserLeaving +(Activity)
        +changeAction +(KeyEvent, int)
        +changeCursorAndColumns +(Cursor, String[], int[])
        +changeFlags +(KeyEvent, int)
        +changeTimeRepeat +(KeyEvent, long, int)
        +checkInputConnectionProxy +(View)
        +clearComposingText +()
        +clearListSelection +()
        +clearMatches +()
        +clearMetaKeyState
        +  type  +(View, Editable, int) in android.text.method.KeyListener +
        +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        +  type  +(View, Editable, int) in android.text.method.MetaKeyKeyListener +
        +  type  +(Editable, int) in android.text.method.MetaKeyKeyListener +
        +clearTestProviderEnabled +(String)
        +clearTestProviderLocation +(String)
        +clearTestProviderStatus +(String)
        +close +()
        +closeContextMenu +()
        +computeDurationHint +()
        +copyPixelsFromBuffer +(Buffer)
        +createInputStream +()
        +createOutputStream +()
        +createWifiLock +(int, String)
        + +
        D  +A +B +C +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +describeContents
        +  type  +() in android.content.res.AssetFileDescriptor +
        +  type  +() in android.graphics.RectF +
        +  type  +() in android.text.Annotation +
        +  type  +() in android.text.style.AbsoluteSizeSpan +
        +  type  +() in android.text.style.AlignmentSpan.Standard +
        +  type  +() in android.text.style.BackgroundColorSpan +
        +  type  +() in android.text.style.BulletSpan +
        +  type  +() in android.text.style.ForegroundColorSpan +
        +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        +  type  +() in android.text.style.QuoteSpan +
        +  type  +() in android.text.style.RelativeSizeSpan +
        +  type  +() in android.text.style.ScaleXSpan +
        +  type  +() in android.text.style.StrikethroughSpan +
        +  type  +() in android.text.style.StyleSpan +
        +  type  +() in android.text.style.SubscriptSpan +
        +  type  +() in android.text.style.SuperscriptSpan +
        +  type  +() in android.text.style.TextAppearanceSpan +
        +  type  +() in android.text.style.TypefaceSpan +
        +  type  +() in android.text.style.URLSpan +
        +  type  +() in android.text.style.UnderlineSpan +
        +deviceHasKey +(int)
        +deviceHasKeys +(int[])
        +didTouchFocusSelect +()
        +dispatchKeyEventPreIme +(KeyEvent)
        +drag +(InstrumentationTestCase, float, float, float, float, int)
        +dragQuarterScreenDown +(InstrumentationTestCase, Activity)
        +dragQuarterScreenUp +(InstrumentationTestCase, Activity)
        +dragViewBy +(InstrumentationTestCase, View, int, int, int)
        +dragViewTo +(InstrumentationTestCase, View, int, int, int)
        +dragViewToBottom
        +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        +  type  +(InstrumentationTestCase, Activity, View, int) in android.test.TouchUtils +
        +dragViewToTop
        +  type  +(InstrumentationTestCase, View) in android.test.TouchUtils +
        +  type  +(InstrumentationTestCase, View, int) in android.test.TouchUtils +
        +dragViewToX +(InstrumentationTestCase, View, int, int)
        +dragViewToY +(InstrumentationTestCase, View, int, int)
        +drawBitmap +(int[], int, int, float, float, int, int, boolean, Paint)
        +dump
        +  type  +(Printer, String) in android.location.Location +
        +  type  +(FileDescriptor, String[]) in android.os.Binder +
        +  type  +(FileDescriptor, String[]) in android.os.IBinder +
        +dumpCapturedView +(String, Object)
        +dumpHprofData
        +  type  +(String) in android.os.Debug +
        +  type  +(String) in dalvik.system.VMDebug +
        +dumpSpans +(CharSequence, Printer, String)
        + +
        E  +A +B +C +D +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +endBatchEdit +()
        +extractText +(ExtractedTextRequest, ExtractedText)
        + +
        F  +A +B +C +D +E +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +findAll +(String)
        +findNext +(boolean)
        +forkAndSpecialize +(int, int, int[], int, int[][])
        +forkSystemServer +(int, int, int[], int, int[][])
        +formatJapaneseNumber +(Editable)
        + +
        G  +A +B +C +D +E +F +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +get +(Context)
        +getAllowFileAccess +()
        +getBackgroundDataSetting +()
        +getBoolean +(int)
        +getBuiltInZoomControls +()
        +getButton +(int)
        +getCapsMode +(CharSequence, int, int)
        +getCharacters +()
        +getDeclaredLength +()
        +getDefaultSensor +(int)
        +getDeviceConfigurationInfo +()
        +getDialog +()
        +getDoubleTapTimeout +()
        +getDrawable
        +  type  +() in android.graphics.drawable.RotateDrawable +
        +  type  +() in android.graphics.drawable.ScaleDrawable +
        +getDropDownAnchor +()
        +getDropDownWidth +()
        +getEditableText +()
        +getFraction +(int, int, int)
        +getGpsStatus +(GpsStatus)
        +getImeActionId +()
        +getImeActionLabel +()
        +getImeOptions +()
        +getInclination +(float[])
        +getInitialScrollX +(TextView, Spannable)
        +getInitialScrollY +(TextView, Spannable)
        +getInputExtras +(boolean)
        +getInputMethodMode +()
        +getInputType
        +  type  +() in android.text.method.DateKeyListener +
        +  type  +() in android.text.method.DateTimeKeyListener +
        +  type  +() in android.text.method.DialerKeyListener +
        +  type  +() in android.text.method.DigitsKeyListener +
        +  type  +() in android.text.method.KeyListener +
        +  type  +() in android.text.method.MultiTapKeyListener +
        +  type  +() in android.text.method.QwertyKeyListener +
        +  type  +() in android.text.method.TextKeyListener +
        +  type  +() in android.text.method.TimeKeyListener +
        +  type  +() in android.widget.TextView +
        +getItem +(int)
        +getKeyProgressIncrement +()
        +getLaunchIntentForPackage
        +  type  +(String) in android.content.pm.PackageManager +
        +  type  +(String) in android.test.mock.MockPackageManager +
        +getLayoutDimension +(int, int)
        +getListSelection +()
        +getListView +()
        +getLoggingMXBean +()
        +getLong
        +  type  +(ContentResolver, String) in android.provider.Settings.System +
        +  type  +(ContentResolver, String, long) in android.provider.Settings.System +
        +getMaxAvailableHeight +(View, int)
        +getMaxKeyCode +()
        +getMetaState
        +  type  +(long) in android.text.method.MetaKeyKeyListener +
        +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        +getNeighboringCellInfo +()
        +getOnChronometerTickListener +()
        +getOnItemClickListener +()
        +getOnItemSelectedListener +()
        +getOrientation +(float[], float[])
        +getOriginalUrl
        +  type  +() in android.webkit.WebHistoryItem +
        +  type  +() in android.webkit.WebView +
        +getPluginData
        +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptHandler +
        +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptRegistry +
        +getPrivateImeOptions +()
        +getRotationMatrix +(float[], float[], float[], float[])
        +getRunningAppProcesses +()
        +getScaledDoubleTapSlop +()
        +getScaledEdgeSlop +()
        +getScaledFadingEdgeLength +()
        +getScaledMaximumDrawingCacheSize +()
        +getScaledMinimumFlingVelocity +()
        +getScaledScrollBarSize +()
        +getScaledTouchSlop +()
        +getScaledWindowTouchSlop +()
        +getSensorList +(int)
        +getSize +(View)
        +getSpanTypeId
        +  type  +() in android.text.Annotation +
        +  type  +() in android.text.style.AbsoluteSizeSpan +
        +  type  +() in android.text.style.AlignmentSpan.Standard +
        +  type  +() in android.text.style.BackgroundColorSpan +
        +  type  +() in android.text.style.BulletSpan +
        +  type  +() in android.text.style.ForegroundColorSpan +
        +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        +  type  +() in android.text.style.QuoteSpan +
        +  type  +() in android.text.style.RelativeSizeSpan +
        +  type  +() in android.text.style.ScaleXSpan +
        +  type  +() in android.text.style.StrikethroughSpan +
        +  type  +() in android.text.style.StyleSpan +
        +  type  +() in android.text.style.SubscriptSpan +
        +  type  +() in android.text.style.SuperscriptSpan +
        +  type  +() in android.text.style.TextAppearanceSpan +
        +  type  +() in android.text.style.TypefaceSpan +
        +  type  +() in android.text.style.URLSpan +
        +  type  +() in android.text.style.UnderlineSpan +
        +getStartX +()
        +getStartY +()
        +getStatSize +()
        +getSubtype +()
        +getSubtypeName +()
        +getSystemSharedLibraryNames
        +  type  +() in android.content.pm.PackageManager +
        +  type  +() in android.test.mock.MockPackageManager +
        +getTextFilter +()
        +getThread +()
        +getTimeZoneDatabaseVersion +()
        +getUserAgentString +()
        +getVerticalAlignment +()
        +getWindowVisibleDisplayFrame +(Rect)
        + +
        H  +A +B +C +D +E +F +G +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +handleKeyDown +(long, int, KeyEvent)
        +handleKeyUp +(long, int, KeyEvent)
        +hasSoftInputMode +()
        +hasWindowFocus +()
        + +
        I  +A +B +C +D +E +F +G +H +L +M +O +P +R +S +T +U +W +Y + TOP +

        +inferStreamType +()
        +intentForPosition +(int)
        +isAboveAnchor +()
        +isBluetoothA2dpOn +()
        +isClippingEnabled +()
        +isDebuggingEnabled +()
        +isFastScrollEnabled +()
        +isFillEnabled +()
        +isHapticFeedbackEnabled +()
        +isInEditMode +()
        +isInputMethodTarget +()
        +isLooping +()
        +isOutsideTouchable +()
        +isPerformingCompletion +()
        +isRoaming +()
        +isSafeMode
        +  type  +() in android.content.pm.PackageManager +
        +  type  +() in android.test.mock.MockPackageManager +
        +isSelectingMetaTracker +(CharSequence, Object)
        +isSmoothScrollbarEnabled +()
        +isTouchable +()
        + +
        L  +A +B +C +D +E +F +G +H +I +M +O +P +R +S +T +U +W +Y + TOP +

        +launchActivityWithIntent +(String, Class<T>, Intent)
        +load
        +  type  +(AssetFileDescriptor, int) in android.media.SoundPool +
        +  type  +(FileDescriptor, long, long, int) in android.media.SoundPool +
        +loadDex +(String, String, int)
        +longClickView +(InstrumentationTestCase, View)
        + +
        M  +A +B +C +D +E +F +G +H +I +L +O +P +R +S +T +U +W +Y + TOP +

        +makeListItems +()
        +mayUseInputMethod +(int)
        +moveCursorToVisibleOffset +()
        +mutate +()
        + +
        O  +A +B +C +D +E +F +G +H +I +L +M +P +R +S +T +U +W +Y + TOP +

        +onBeginBatchEdit +()
        +onCheckIsTextEditor +()
        +onCommitCompletion +(CompletionInfo)
        +onContentChanged +()
        +onCreateInputConnection +(EditorInfo)
        +onDoubleTap +(MotionEvent)
        +onDoubleTapEvent +(MotionEvent)
        +onEditorAction +(int)
        +onEndBatchEdit +()
        +onFinishTemporaryDetach +()
        +onKeyOther
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ArrowKeyMovementMethod +
        +  type  +(View, Editable, KeyEvent) in android.text.method.BaseKeyListener +
        +  type  +(View, Editable, KeyEvent) in android.text.method.KeyListener +
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.MovementMethod +
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ScrollingMovementMethod +
        +onKeyPreIme +(int, KeyEvent)
        +onPrivateIMECommand +(String, Bundle)
        +onSelectionChanged +(int, int)
        +onSingleTapConfirmed +(MotionEvent)
        +onStartTemporaryDetach +()
        +onTextContextMenuItem +(int)
        +onUserInteraction +()
        +onUserLeaveHint +()
        +openAssetFile +(Uri, String)
        +openAssetFileDescriptor +(Uri, String)
        +openOutputStream +(Uri, String)
        +openRawResource +(int, TypedValue)
        + +
        P  +A +B +C +D +E +F +G +H +I +L +M +O +R +S +T +U +W +Y + TOP +

        +parseBundleExtra +(String, AttributeSet, Bundle)
        +parseBundleExtras +(XmlResourceParser, Bundle)
        +peekService +(Context, Intent)
        +performHapticFeedback
        +  type  +(int) in android.view.View +
        +  type  +(int, int) in android.view.View +
        +playSoundEffect +(int, float)
        +putLong +(ContentResolver, String, long)
        + +
        R  +A +B +C +D +E +F +G +H +I +L +M +O +P +S +T +U +W +Y + TOP +

        +readFromParcel +(Parcel)
        +registerListener
        +  type  +(SensorEventListener, Sensor, int) in android.hardware.SensorManager +
        +  type  +(SensorEventListener, Sensor, int, Handler) in android.hardware.SensorManager +
        +remapCoordinateSystem +(float[], int, int, float[])
        +removeAt +(int)
        +removeGpsStatusListener +(Listener)
        +removeOnScrollChangedListener +(OnScrollChangedListener)
        +removePropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        +removeTestProvider +(String)
        +removeUpdates +(PendingIntent)
        +replaceExtras
        +  type  +(Intent) in android.content.Intent +
        +  type  +(Bundle) in android.content.Intent +
        +requestChildRectangleOnScreen +(View, Rect, boolean)
        +requestLocationUpdates +(String, long, float, PendingIntent)
        +resetLockedMeta +(long)
        +restartPackage +(String)
        +restorePicture +(Bundle, File)
        +runTestOnUiThread +(Runnable)
        + +
        S  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +T +U +W +Y + TOP +

        +savePicture +(Bundle, File)
        +scrollToBottom +(InstrumentationTestCase, Activity, ViewGroup)
        +scrollToTop +(InstrumentationTestCase, Activity, ViewGroup)
        +sendExtraCommand +(String, String, Bundle)
        +setAllowFileAccess +(boolean)
        +setBitmap +(int, String, Bitmap)
        +setBluetoothA2dpOn +(boolean)
        +setBoolean +(int, String, boolean)
        +setBuiltInZoomControls +(boolean)
        +setButton
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(CharSequence, Message) in android.app.AlertDialog +
        +setByte +(int, String, byte)
        +setCamera +(Camera)
        +setChar +(int, String, char)
        +setCharSequence +(int, String, CharSequence)
        +setClippingEnabled +(boolean)
        +setCompoundDrawablesWithIntrinsicBounds +(int, int, int, int)
        +setDouble +(int, String, double)
        +setDropDownAnchor +(int)
        +setDropDownWidth +(int)
        +setExtractedText +(ExtractedText)
        +setFastScrollEnabled +(boolean)
        +setFillEnabled +(boolean)
        +setFloat +(int, String, float)
        +setFooterDividersEnabled +(boolean)
        +setHapticFeedbackEnabled +(boolean)
        +setHeaderDividersEnabled +(boolean)
        +setImageViewBitmap +(int, Bitmap)
        +setImeActionLabel +(CharSequence, int)
        +setImeOptions +(int)
        +setInexactRepeating +(int, long, long, PendingIntent)
        +setInputExtras +(int)
        +setInputMethodMode +(int)
        +setInputType +(int)
        +setInt +(int, String, int)
        +setKeyProgressIncrement +(int)
        +setListSelection +(int)
        +setLong +(int, String, long)
        +setMaxDuration +(int)
        +setMaxFileSize +(long)
        +setNetworkAvailable +(boolean)
        +setOnChronometerTickListener +(OnChronometerTickListener)
        +setOnClickPendingIntent +(int, PendingIntent)
        +setOnDoubleTapListener +(OnDoubleTapListener)
        +setOnEditorActionListener +(OnEditorActionListener)
        +setOnErrorListener +(OnErrorListener)
        +setOneShotPreviewCallback +(PreviewCallback)
        +setOnInfoListener
        +  type  +(OnInfoListener) in android.media.MediaPlayer +
        +  type  +(OnInfoListener) in android.media.MediaRecorder +
        +setOnVideoSizeChangedListener +(OnVideoSizeChangedListener)
        +setOutputFile +(FileDescriptor)
        +setOutsideTouchable +(boolean)
        +setPrivateImeOptions +(String)
        +setRawInputType +(int)
        +setScrollContainer +(boolean)
        +setShort +(int, String, short)
        +setSmoothScrollbarEnabled +(boolean)
        +setSoftInputMode +(int)
        +setStaticTransformationsEnabled +(boolean)
        +setString +(int, String, String)
        +setTestProviderEnabled +(String, boolean)
        +setTestProviderLocation +(String, Location)
        +setTestProviderStatus +(String, int, Bundle, long)
        +setTextColor +(int, int)
        +setTouchable +(boolean)
        +setTouchInterceptor +(OnTouchListener)
        +setUri +(int, String, Uri)
        +setUserAgentString +(String)
        +setVideoEncoder +(int)
        +setVideoFrameRate +(int)
        +setVideoSize +(int, int)
        +setVideoSource +(int)
        +setView +(View, int, int, int, int)
        +setViewResource +(int)
        +setVisible +(boolean)
        +setWindowAnimations +(int)
        +setWindowLayoutMode +(int, int)
        +sort +(Comparator<? super T>)
        + +
        T  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +U +W +Y + TOP +

        +toShortString
        +  type  +() in android.graphics.Rect +
        +  type  +() in android.view.animation.Transformation +
        + +
        U  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +W +Y + TOP +

        +unregisterListener
        +  type  +(SensorEventListener) in android.hardware.SensorManager +
        +  type  +(SensorEventListener, Sensor) in android.hardware.SensorManager +
        +update
        +  type  +() in android.widget.PopupWindow +
        +  type  +(int, int, int, int, boolean) in android.widget.PopupWindow +
        + +
        W  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +Y + TOP +

        +writeToParcel
        +  type  +(Parcel, int) in android.content.res.AssetFileDescriptor +
        +  type  +(Parcel, int) in android.graphics.RectF +
        +  type  +(Parcel, int) in android.text.Annotation +
        +  type  +(Parcel, int) in android.text.style.AbsoluteSizeSpan +
        +  type  +(Parcel, int) in android.text.style.AlignmentSpan.Standard +
        +  type  +(Parcel, int) in android.text.style.BackgroundColorSpan +
        +  type  +(Parcel, int) in android.text.style.BulletSpan +
        +  type  +(Parcel, int) in android.text.style.ForegroundColorSpan +
        +  type  +(Parcel, int) in android.text.style.LeadingMarginSpan.Standard +
        +  type  +(Parcel, int) in android.text.style.QuoteSpan +
        +  type  +(Parcel, int) in android.text.style.RelativeSizeSpan +
        +  type  +(Parcel, int) in android.text.style.ScaleXSpan +
        +  type  +(Parcel, int) in android.text.style.StrikethroughSpan +
        +  type  +(Parcel, int) in android.text.style.StyleSpan +
        +  type  +(Parcel, int) in android.text.style.SubscriptSpan +
        +  type  +(Parcel, int) in android.text.style.SuperscriptSpan +
        +  type  +(Parcel, int) in android.text.style.TextAppearanceSpan +
        +  type  +(Parcel, int) in android.text.style.TypefaceSpan +
        +  type  +(Parcel, int) in android.text.style.URLSpan +
        +  type  +(Parcel, int) in android.text.style.UnderlineSpan +
        + +
        Y  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W + TOP +

        +yieldIfContendedSafely +()
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/methods_index_all.html b/docs/html/sdk/api_diff/3/changes/methods_index_all.html new file mode 100644 index 0000000000000000000000000000000000000000..22492a352290e06b2de2f1efd3e99fdfe01a9ee5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/methods_index_all.html @@ -0,0 +1,1600 @@ + + + + + + + + + +Method Differences Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +Methods +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +addGpsStatusListener +(Listener)
        +addOnScrollChangedListener +(OnScrollChangedListener)
        +addPropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        +addRequirements +(Predicate<TestMethod>)
        +addTestProvider +(String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int)
        +adjustMetaAfterKeypress +(long)
        +appendEscapedSQLString +(StringBuilder, String)
        +applyDisplay +(int, Rect, Rect)
        + +
        B  +A +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +beginBatchEdit +()
        +bringPointIntoView +(int)
        + +
        C  +A +B +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +calculateLength +(CharSequence, boolean)
        +callActivityOnUserLeaving +(Activity)
        +changeAction +(KeyEvent, int)
        +changeCursorAndColumns +(Cursor, String[], int[])
        +changeDebugPort +(int)
        +changeFlags +(KeyEvent, int)
        +changeTimeRepeat +(KeyEvent, long, int)
        +checkInputConnectionProxy +(View)
        +clearComposingText +()
        +clearListSelection +()
        +clearMatches +()
        +clearMetaKeyState
        +  type  +(View, Editable, int) in android.text.method.KeyListener +
        +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        +  type  +(View, Editable, int) in android.text.method.MetaKeyKeyListener +
        +  type  +(Editable, int) in android.text.method.MetaKeyKeyListener +
        +clearTestProviderEnabled +(String)
        +clearTestProviderLocation +(String)
        +clearTestProviderStatus +(String)
        +clone +()
        +close +()
        +closeContextMenu +()
        +computeDurationHint +()
        +copyPixelsFromBuffer +(Buffer)
        +createInputStream +()
        +createOutputStream +()
        +createWifiLock +(int, String)
        + +
        D  +A +B +C +E +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +describeContents
        +  type  +() in android.content.res.AssetFileDescriptor +
        +  type  +() in android.graphics.RectF +
        +  type  +() in android.text.Annotation +
        +  type  +() in android.text.style.AbsoluteSizeSpan +
        +  type  +() in android.text.style.AlignmentSpan.Standard +
        +  type  +() in android.text.style.BackgroundColorSpan +
        +  type  +() in android.text.style.BulletSpan +
        +  type  +() in android.text.style.ForegroundColorSpan +
        +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        +  type  +() in android.text.style.QuoteSpan +
        +  type  +() in android.text.style.RelativeSizeSpan +
        +  type  +() in android.text.style.ScaleXSpan +
        +  type  +() in android.text.style.StrikethroughSpan +
        +  type  +() in android.text.style.StyleSpan +
        +  type  +() in android.text.style.SubscriptSpan +
        +  type  +() in android.text.style.SuperscriptSpan +
        +  type  +() in android.text.style.TextAppearanceSpan +
        +  type  +() in android.text.style.TypefaceSpan +
        +  type  +() in android.text.style.URLSpan +
        +  type  +() in android.text.style.UnderlineSpan +
        +deviceHasKey +(int)
        +deviceHasKeys +(int[])
        +didTouchFocusSelect +()
        +dispatchKeyEventPreIme +(KeyEvent)
        +drag
        +  type  +(InstrumentationTestCase, float, float, float, float, int) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, float, float, float, float, int) in android.test.TouchUtils +
        +dragQuarterScreenDown
        +  type  +(InstrumentationTestCase, Activity) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase) in android.test.TouchUtils +
        +dragQuarterScreenUp
        +  type  +(InstrumentationTestCase, Activity) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase) in android.test.TouchUtils +
        +dragViewBy
        +  type  +(InstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        +dragViewTo
        +  type  +(InstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View, int, int, int) in android.test.TouchUtils +
        +dragViewToBottom
        +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        +  type  +(InstrumentationTestCase, Activity, View, int) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        +  type  +(InstrumentationTestCase, Activity, View) in android.test.TouchUtils +
        +dragViewToTop
        +  type  +(InstrumentationTestCase, View) in android.test.TouchUtils +
        +  type  +(InstrumentationTestCase, View, int) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        +dragViewToX
        +  type  +(InstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        +dragViewToY
        +  type  +(InstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View, int, int) in android.test.TouchUtils +
        +drawBitmap +(int[], int, int, float, float, int, int, boolean, Paint)
        +dump
        +  type  +(Printer, String) in android.location.Location +
        +  type  +(FileDescriptor, String[]) in android.os.Binder +
        +  type  +(FileDescriptor, String[]) in android.os.IBinder +
        +dumpCapturedView +(String, Object)
        +dumpHprofData
        +  type  +(String) in android.os.Debug +
        +  type  +(String) in dalvik.system.VMDebug +
        +dumpSpans +(CharSequence, Printer, String)
        + +
        E  +A +B +C +D +F +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +endBatchEdit +()
        +extractText +(ExtractedTextRequest, ExtractedText)
        + +
        F  +A +B +C +D +E +G +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +findAll +(String)
        +findNext +(boolean)
        +forkAndSpecialize
        +  type  +(int, int, int[], int, int[][]) in dalvik.system.Zygote +
        +  type  +(int, int, int[], boolean, int[][]) in dalvik.system.Zygote +
        +forkSystemServer
        +  type  +(int, int, int[], int, int[][]) in dalvik.system.Zygote +
        +  type  +(int, int, int[], boolean, int[][]) in dalvik.system.Zygote +
        +formatJapaneseNumber +(Editable)
        +forName +(String)
        + +
        G  +A +B +C +D +E +F +H +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +get +(Context)
        +getAllowFileAccess +()
        +getBackgroundDataSetting +()
        +getBoolean +(int)
        +getBuiltInZoomControls +()
        +getButton +(int)
        +getCapsMode +(CharSequence, int, int)
        +getCharacters +()
        +getClasses +()
        +getColumnIndex
        +  type  +(String) in android.database.Cursor +
        +  type  +(String) in android.database.CursorWrapper +
        +getConstructors +()
        +getCount +()
        +getDeclaredClasses +()
        +getDeclaredConstructors +()
        +getDeclaredLength +()
        +getDefaultSensor +(int)
        +getDeviceConfigurationInfo +()
        +getDialog +()
        +getDoubleTapTimeout +()
        +getDrawable
        +  type  +() in android.graphics.drawable.RotateDrawable +
        +  type  +() in android.graphics.drawable.ScaleDrawable +
        +getDropDownAnchor +()
        +getDropDownWidth +()
        +getEdgeSlop +()
        +getEditableText +()
        +getFadingEdgeLength +()
        +getFraction +(int, int, int)
        +getGpsStatus +(GpsStatus)
        +getHandler +()
        +getImeActionId +()
        +getImeActionLabel +()
        +getImeOptions +()
        +getInclination +(float[])
        +getInitialScrollX +(TextView, Spannable)
        +getInitialScrollY +(TextView, Spannable)
        +getInputExtras +(boolean)
        +getInputMethodMode +()
        +getInputType
        +  type  +() in android.text.method.DateKeyListener +
        +  type  +() in android.text.method.DateTimeKeyListener +
        +  type  +() in android.text.method.DialerKeyListener +
        +  type  +() in android.text.method.DigitsKeyListener +
        +  type  +() in android.text.method.KeyListener +
        +  type  +() in android.text.method.MultiTapKeyListener +
        +  type  +() in android.text.method.QwertyKeyListener +
        +  type  +() in android.text.method.TextKeyListener +
        +  type  +() in android.text.method.TimeKeyListener +
        +  type  +() in android.widget.TextView +
        +getInterfaces +()
        +getItem
        +  type  +(int) in android.view.Menu +
        +  type  +(int) in android.widget.CursorAdapter +
        +getItemClickListener +()
        +getItemId +(int)
        +getItemSelectedListener +()
        +getKeyProgressIncrement +()
        +getLaunchIntentForPackage
        +  type  +(String) in android.content.pm.PackageManager +
        +  type  +(String) in android.test.mock.MockPackageManager +
        +getLayoutDimension +(int, int)
        +getListSelection +()
        +getListView +()
        +getLoggingMXBean +()
        +getLong
        +  type  +(ContentResolver, String) in android.provider.Settings.System +
        +  type  +(ContentResolver, String, long) in android.provider.Settings.System +
        +getMaxAvailableHeight +(View, int)
        +getMaximumDrawingCacheSize +()
        +getMaxKeyCode +()
        +getMetaState
        +  type  +(long) in android.text.method.MetaKeyKeyListener +
        +  type  +(long, int) in android.text.method.MetaKeyKeyListener +
        +getMinimumFlingVelocity +()
        +getNeighboringCellInfo +()
        +getOnChronometerTickListener +()
        +getOnItemClickListener +()
        +getOnItemSelectedListener +()
        +getOrientation +(float[], float[])
        +getOriginalUrl
        +  type  +() in android.webkit.WebHistoryItem +
        +  type  +() in android.webkit.WebView +
        +getPluginData
        +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptHandler +
        +  type  +(String, Map<String, String>) in android.webkit.UrlInterceptRegistry +
        +getPrivateImeOptions +()
        +getProxyClass +(ClassLoader, Class<?>)
        +getRotationMatrix +(float[], float[], float[], float[])
        +getRunningAppProcesses +()
        +getScaledDoubleTapSlop +()
        +getScaledEdgeSlop +()
        +getScaledFadingEdgeLength +()
        +getScaledMaximumDrawingCacheSize +()
        +getScaledMinimumFlingVelocity +()
        +getScaledScrollBarSize +()
        +getScaledTouchSlop +()
        +getScaledWindowTouchSlop +()
        +getScrollBarSize +()
        +getSensorList +(int)
        +getSensors +()
        +getSize +(View)
        +getSpanTypeId
        +  type  +() in android.text.Annotation +
        +  type  +() in android.text.style.AbsoluteSizeSpan +
        +  type  +() in android.text.style.AlignmentSpan.Standard +
        +  type  +() in android.text.style.BackgroundColorSpan +
        +  type  +() in android.text.style.BulletSpan +
        +  type  +() in android.text.style.ForegroundColorSpan +
        +  type  +() in android.text.style.LeadingMarginSpan.Standard +
        +  type  +() in android.text.style.QuoteSpan +
        +  type  +() in android.text.style.RelativeSizeSpan +
        +  type  +() in android.text.style.ScaleXSpan +
        +  type  +() in android.text.style.StrikethroughSpan +
        +  type  +() in android.text.style.StyleSpan +
        +  type  +() in android.text.style.SubscriptSpan +
        +  type  +() in android.text.style.SuperscriptSpan +
        +  type  +() in android.text.style.TextAppearanceSpan +
        +  type  +() in android.text.style.TypefaceSpan +
        +  type  +() in android.text.style.URLSpan +
        +  type  +() in android.text.style.UnderlineSpan +
        +getStartX +()
        +getStartY +()
        +getStatSize +()
        +getSubtype +()
        +getSubtypeName +()
        +getSurrogate +(String, Map<String, String>)
        +getSystemSharedLibraryNames
        +  type  +() in android.content.pm.PackageManager +
        +  type  +() in android.test.mock.MockPackageManager +
        +getTargetIntent +()
        +getTextFilter +()
        +getThread +()
        +getTimeZoneDatabaseVersion +()
        +getTouchSlop +()
        +getUserAgent +()
        +getUserAgentString +()
        +getVerticalAlignment +()
        +getWindowTouchSlop +()
        +getWindowVisibleDisplayFrame +(Rect)
        +getZoomControls +()
        + +
        H  +A +B +C +D +E +F +G +I +L +M +O +P +R +S +T +U +W +Y + TOP +

        +handleKeyDown +(long, int, KeyEvent)
        +handleKeyUp +(long, int, KeyEvent)
        +hasSoftInputMode +()
        +hasWindowFocus +()
        + +
        I  +A +B +C +D +E +F +G +H +L +M +O +P +R +S +T +U +W +Y + TOP +

        +inferStreamType +()
        +intentForPosition +(int)
        +isAboveAnchor +()
        +isBluetoothA2dpOn +()
        +isClippingEnabled +()
        +isCookielessProxyUrl +(String)
        +isDebuggingEnabled +()
        +isFastScrollEnabled +()
        +isFillEnabled +()
        +isHapticFeedbackEnabled +()
        +isInEditMode +()
        +isInputMethodTarget +()
        +isLooping +()
        +isOutsideTouchable +()
        +isPerformingCompletion +()
        +isRoaming +()
        +isSafeMode
        +  type  +() in android.content.pm.PackageManager +
        +  type  +() in android.test.mock.MockPackageManager +
        +isSelectingMetaTracker +(CharSequence, Object)
        +isSmoothScrollbarEnabled +()
        +isTouchable +()
        + +
        L  +A +B +C +D +E +F +G +H +I +M +O +P +R +S +T +U +W +Y + TOP +

        +launchActivityWithIntent +(String, Class<T>, Intent)
        +load
        +  type  +(AssetFileDescriptor, int) in android.media.SoundPool +
        +  type  +(FileDescriptor, long, long, int) in android.media.SoundPool +
        +loadDex +(String, String, int)
        +longClickView
        +  type  +(InstrumentationTestCase, View) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        + +
        M  +A +B +C +D +E +F +G +H +I +L +O +P +R +S +T +U +W +Y + TOP +

        +makeListItems +()
        +mayUseInputMethod +(int)
        +moveCursorToVisibleOffset +()
        +mutate +()
        + +
        O  +A +B +C +D +E +F +G +H +I +L +M +P +R +S +T +U +W +Y + TOP +

        +onBeginBatchEdit +()
        +onCheckIsTextEditor +()
        +onCommitCompletion +(CompletionInfo)
        +onContentChanged +()
        +onCreateInputConnection +(EditorInfo)
        +onDoubleTap +(MotionEvent)
        +onDoubleTapEvent +(MotionEvent)
        +onEditorAction +(int)
        +onEndBatchEdit +()
        +onFinishTemporaryDetach +()
        +onGlobalFocusChanged +(View, View)
        +onKeyOther
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ArrowKeyMovementMethod +
        +  type  +(View, Editable, KeyEvent) in android.text.method.BaseKeyListener +
        +  type  +(View, Editable, KeyEvent) in android.text.method.KeyListener +
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.MovementMethod +
        +  type  +(TextView, Spannable, KeyEvent) in android.text.method.ScrollingMovementMethod +
        +onKeyPreIme +(int, KeyEvent)
        +onPrivateIMECommand +(String, Bundle)
        +onRestoreInstanceState +(Parcelable)
        +onSaveInstanceState +()
        +onSelectionChanged +(int, int)
        +onSingleTapConfirmed +(MotionEvent)
        +onStartTemporaryDetach +()
        +onTextContextMenuItem +(int)
        +onUserInteraction +()
        +onUserLeaveHint +()
        +openAssetFile +(Uri, String)
        +openAssetFileDescriptor +(Uri, String)
        +openOutputStream +(Uri, String)
        +openRawResource +(int, TypedValue)
        + +
        P  +A +B +C +D +E +F +G +H +I +L +M +O +R +S +T +U +W +Y + TOP +

        +parse +(String)
        +parseBundleExtra +(String, AttributeSet, Bundle)
        +parseBundleExtras +(XmlResourceParser, Bundle)
        +peekService +(Context, Intent)
        +performHapticFeedback
        +  type  +(int) in android.view.View +
        +  type  +(int, int) in android.view.View +
        +playSoundEffect
        +  type  +(int, float) in android.media.AudioManager +
        +  type  +(int) in android.view.View +
        +prepare +()
        +putLong +(ContentResolver, String, long)
        + +
        R  +A +B +C +D +E +F +G +H +I +L +M +O +P +S +T +U +W +Y + TOP +

        +readFromParcel +(Parcel)
        +readHashMap +(ClassLoader)
        +readMap +(Map, ClassLoader)
        +registerListener
        +  type  +(SensorEventListener, Sensor, int) in android.hardware.SensorManager +
        +  type  +(SensorEventListener, Sensor, int, Handler) in android.hardware.SensorManager +
        +  type  +(SensorListener, int) in android.hardware.SensorManager +
        +  type  +(SensorListener, int, int) in android.hardware.SensorManager +
        +remapCoordinateSystem +(float[], int, int, float[])
        +removeAt +(int)
        +removeGpsStatusListener +(Listener)
        +removeOnScrollChangedListener +(OnScrollChangedListener)
        +removePropertyChangeListener
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Packer +
        +  type  +(PropertyChangeListener) in java.util.jar.Pack200.Unpacker +
        +  type  +(PropertyChangeListener) in java.util.logging.LogManager +
        +removeTestProvider +(String)
        +removeUpdates +(PendingIntent)
        +replaceExtras
        +  type  +(Intent) in android.content.Intent +
        +  type  +(Bundle) in android.content.Intent +
        +requestChildRectangleOnScreen +(View, Rect, boolean)
        +requestLocationUpdates +(String, long, float, PendingIntent)
        +resetLockedMeta +(long)
        +restartPackage +(String)
        +restorePicture +(Bundle, File)
        +runTestOnUiThread +(Runnable)
        + +
        S  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +T +U +W +Y + TOP +

        +savePicture +(Bundle, File)
        +scrollToBottom
        +  type  +(InstrumentationTestCase, Activity, ViewGroup) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, ViewGroup) in android.test.TouchUtils +
        +scrollToTop
        +  type  +(InstrumentationTestCase, Activity, ViewGroup) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, ViewGroup) in android.test.TouchUtils +
        +sendExtraCommand +(String, String, Bundle)
        +service +(String, Map<String, String>)
        +setAllowFileAccess +(boolean)
        +setBitmap +(int, String, Bitmap)
        +setBluetoothA2dpOn +(boolean)
        +setBoolean +(int, String, boolean)
        +setBuiltInZoomControls +(boolean)
        +setButton
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(CharSequence, Message) in android.app.AlertDialog +
        +  type  +(int, CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(int, CharSequence, Message) in android.app.AlertDialog +
        +setButton2
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(CharSequence, Message) in android.app.AlertDialog +
        +setButton3
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(CharSequence, Message) in android.app.AlertDialog +
        +setByte +(int, String, byte)
        +setCamera +(Camera)
        +setChar +(int, String, char)
        +setCharSequence +(int, String, CharSequence)
        +setClippingEnabled +(boolean)
        +setCompoundDrawablesWithIntrinsicBounds +(int, int, int, int)
        +setDouble +(int, String, double)
        +setDropDownAnchor +(int)
        +setDropDownWidth +(int)
        +setExtractedText +(ExtractedText)
        +setFastScrollEnabled +(boolean)
        +setFillEnabled +(boolean)
        +setFloat +(int, String, float)
        +setFooterDividersEnabled +(boolean)
        +setHapticFeedbackEnabled +(boolean)
        +setHeaderDividersEnabled +(boolean)
        +setImageViewBitmap +(int, Bitmap)
        +setImeActionLabel +(CharSequence, int)
        +setImeOptions +(int)
        +setInexactRepeating +(int, long, long, PendingIntent)
        +setInputExtras +(int)
        +setInputMethodMode +(int)
        +setInputType +(int)
        +setInt +(int, String, int)
        +setKeyProgressIncrement +(int)
        +setListSelection +(int)
        +setLong +(int, String, long)
        +setMaxDuration +(int)
        +setMaxFileSize +(long)
        +setNetworkAvailable +(boolean)
        +setOnChronometerTickListener +(OnChronometerTickListener)
        +setOnClickPendingIntent +(int, PendingIntent)
        +setOnDoubleTapListener +(OnDoubleTapListener)
        +setOnEditorActionListener +(OnEditorActionListener)
        +setOnErrorListener +(OnErrorListener)
        +setOneShotPreviewCallback +(PreviewCallback)
        +setOnInfoListener
        +  type  +(OnInfoListener) in android.media.MediaPlayer +
        +  type  +(OnInfoListener) in android.media.MediaRecorder +
        +setOnVideoSizeChangedListener +(OnVideoSizeChangedListener)
        +setOutputFile +(FileDescriptor)
        +setOutsideTouchable +(boolean)
        +setPreviewDisplay +(SurfaceHolder)
        +setPrivateImeOptions +(String)
        +setRawInputType +(int)
        +setScrollContainer +(boolean)
        +setShort +(int, String, short)
        +setSmoothScrollbarEnabled +(boolean)
        +setSoftInputMode +(int)
        +setStaticTransformationsEnabled +(boolean)
        +setString +(int, String, String)
        +setTestProviderEnabled +(String, boolean)
        +setTestProviderLocation +(String, Location)
        +setTestProviderStatus +(String, int, Bundle, long)
        +setTextColor +(int, int)
        +setTouchable +(boolean)
        +setTouchInterceptor +(OnTouchListener)
        +setUri +(int, String, Uri)
        +setUserAgent +(int)
        +setUserAgentString +(String)
        +setVideoEncoder +(int)
        +setVideoFrameRate +(int)
        +setVideoSize +(int, int)
        +setVideoSource +(int)
        +setView +(View, int, int, int, int)
        +setViewResource +(int)
        +setVisible +(boolean)
        +setWindowAnimations +(int)
        +setWindowLayoutMode +(int, int)
        +sort +(Comparator<? super T>)
        + +
        T  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +U +W +Y + TOP +

        +toShortString
        +  type  +() in android.graphics.Rect +
        +  type  +() in android.view.animation.Transformation +
        + +
        U  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +W +Y + TOP +

        +unregisterListener
        +  type  +(SensorEventListener) in android.hardware.SensorManager +
        +  type  +(SensorEventListener, Sensor) in android.hardware.SensorManager +
        +  type  +(SensorListener) in android.hardware.SensorManager +
        +  type  +(SensorListener, int) in android.hardware.SensorManager +
        +update
        +  type  +() in android.widget.PopupWindow +
        +  type  +(int, int, int, int, boolean) in android.widget.PopupWindow +
        + +
        W  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +Y + TOP +

        +writeMap +(Map)
        +writeToParcel
        +  type  +(Parcel, int) in android.content.res.AssetFileDescriptor +
        +  type  +(Parcel, int) in android.graphics.RectF +
        +  type  +(Parcel, int) in android.text.Annotation +
        +  type  +(Parcel, int) in android.text.style.AbsoluteSizeSpan +
        +  type  +(Parcel, int) in android.text.style.AlignmentSpan.Standard +
        +  type  +(Parcel, int) in android.text.style.BackgroundColorSpan +
        +  type  +(Parcel, int) in android.text.style.BulletSpan +
        +  type  +(Parcel, int) in android.text.style.ForegroundColorSpan +
        +  type  +(Parcel, int) in android.text.style.LeadingMarginSpan.Standard +
        +  type  +(Parcel, int) in android.text.style.QuoteSpan +
        +  type  +(Parcel, int) in android.text.style.RelativeSizeSpan +
        +  type  +(Parcel, int) in android.text.style.ScaleXSpan +
        +  type  +(Parcel, int) in android.text.style.StrikethroughSpan +
        +  type  +(Parcel, int) in android.text.style.StyleSpan +
        +  type  +(Parcel, int) in android.text.style.SubscriptSpan +
        +  type  +(Parcel, int) in android.text.style.SuperscriptSpan +
        +  type  +(Parcel, int) in android.text.style.TextAppearanceSpan +
        +  type  +(Parcel, int) in android.text.style.TypefaceSpan +
        +  type  +(Parcel, int) in android.text.style.URLSpan +
        +  type  +(Parcel, int) in android.text.style.UnderlineSpan +
        + +
        Y  +A +B +C +D +E +F +G +H +I +L +M +O +P +R +S +T +U +W + TOP +

        +yieldIfContended +()
        +yieldIfContendedSafely +()
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/methods_index_changes.html b/docs/html/sdk/api_diff/3/changes/methods_index_changes.html new file mode 100644 index 0000000000000000000000000000000000000000..1b1b305b9a44d0eb91dabda23a669212b513ea05 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/methods_index_changes.html @@ -0,0 +1,466 @@ + + + + + + + + + +Method Changes Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Methods +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + +
        A  +C +D +F +G +I +L +O +P +R +S +U +W +Y + TOP +

        +addRequirements +(Predicate<TestMethod>)
        +appendEscapedSQLString +(StringBuilder, String)
        + +
        C  +A +D +F +G +I +L +O +P +R +S +U +W +Y + TOP +

        +changeDebugPort +(int)
        +clone +()
        + +
        D  +A +C +F +G +I +L +O +P +R +S +U +W +Y + TOP +

        +drag +(ActivityInstrumentationTestCase, float, float, float, float, int)
        +dragQuarterScreenDown +(ActivityInstrumentationTestCase)
        +dragQuarterScreenUp +(ActivityInstrumentationTestCase)
        +dragViewBy +(ActivityInstrumentationTestCase, View, int, int, int)
        +dragViewTo +(ActivityInstrumentationTestCase, View, int, int, int)
        +dragViewToBottom
        +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        +  type  +(InstrumentationTestCase, Activity, View) in android.test.TouchUtils +
        +dragViewToTop
        +  type  +(ActivityInstrumentationTestCase, View) in android.test.TouchUtils +
        +  type  +(ActivityInstrumentationTestCase, View, int) in android.test.TouchUtils +
        +dragViewToX +(ActivityInstrumentationTestCase, View, int, int)
        +dragViewToY +(ActivityInstrumentationTestCase, View, int, int)
        + +
        F  +A +C +D +G +I +L +O +P +R +S +U +W +Y + TOP +

        +forkAndSpecialize +(int, int, int[], boolean, int[][])
        +forkSystemServer +(int, int, int[], boolean, int[][])
        +forName +(String)
        + +
        G  +A +C +D +F +I +L +O +P +R +S +U +W +Y + TOP +

        +getClasses +()
        +getColumnIndex
        +  type  +(String) in android.database.Cursor +
        +  type  +(String) in android.database.CursorWrapper +
        +getConstructors +()
        +getCount +()
        +getDeclaredClasses +()
        +getDeclaredConstructors +()
        +getEdgeSlop +()
        +getFadingEdgeLength +()
        +getHandler +()
        +getInterfaces +()
        +getItem +(int)
        +getItemClickListener +()
        +getItemId +(int)
        +getItemSelectedListener +()
        +getMaximumDrawingCacheSize +()
        +getMinimumFlingVelocity +()
        +getProxyClass +(ClassLoader, Class<?>)
        +getScrollBarSize +()
        +getSensors +()
        +getSurrogate +(String, Map<String, String>)
        +getTargetIntent +()
        +getTouchSlop +()
        +getUserAgent +()
        +getWindowTouchSlop +()
        +getZoomControls +()
        + +
        I  +A +C +D +F +G +L +O +P +R +S +U +W +Y + TOP +

        +isCookielessProxyUrl +(String)
        + +
        L  +A +C +D +F +G +I +O +P +R +S +U +W +Y + TOP +

        +longClickView +(ActivityInstrumentationTestCase, View)
        + +
        O  +A +C +D +F +G +I +L +P +R +S +U +W +Y + TOP +

        +onGlobalFocusChanged +(View, View)
        +onRestoreInstanceState +(Parcelable)
        +onSaveInstanceState +()
        + +
        P  +A +C +D +F +G +I +L +O +R +S +U +W +Y + TOP +

        +parse +(String)
        +playSoundEffect +(int)
        +prepare +()
        + +
        R  +A +C +D +F +G +I +L +O +P +S +U +W +Y + TOP +

        +readHashMap +(ClassLoader)
        +readMap +(Map, ClassLoader)
        +registerListener
        +  type  +(SensorListener, int) in android.hardware.SensorManager +
        +  type  +(SensorListener, int, int) in android.hardware.SensorManager +
        + +
        S  +A +C +D +F +G +I +L +O +P +R +U +W +Y + TOP +

        +scrollToBottom +(ActivityInstrumentationTestCase, ViewGroup)
        +scrollToTop +(ActivityInstrumentationTestCase, ViewGroup)
        +service +(String, Map<String, String>)
        +setButton
        +  type  +(int, CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(int, CharSequence, Message) in android.app.AlertDialog +
        +setButton2
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(CharSequence, Message) in android.app.AlertDialog +
        +setButton3
        +  type  +(CharSequence, OnClickListener) in android.app.AlertDialog +
        +  type  +(CharSequence, Message) in android.app.AlertDialog +
        +setPreviewDisplay +(SurfaceHolder)
        +setUserAgent +(int)
        + +
        U  +A +C +D +F +G +I +L +O +P +R +S +W +Y + TOP +

        +unregisterListener
        +  type  +(SensorListener) in android.hardware.SensorManager +
        +  type  +(SensorListener, int) in android.hardware.SensorManager +
        + +
        W  +A +C +D +F +G +I +L +O +P +R +S +U +Y + TOP +

        +writeMap +(Map)
        + +
        Y  +A +C +D +F +G +I +L +O +P +R +S +U +W + TOP +

        +yieldIfContended +()
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/methods_index_removals.html b/docs/html/sdk/api_diff/3/changes/methods_index_removals.html new file mode 100644 index 0000000000000000000000000000000000000000..bbce14487297df3493c13df6b7f87d2fb0d688ab --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/methods_index_removals.html @@ -0,0 +1,62 @@ + + + + + + + + + +Method Removals Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Methods +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/packages_index_additions.html b/docs/html/sdk/api_diff/3/changes/packages_index_additions.html new file mode 100644 index 0000000000000000000000000000000000000000..ccd54fdc5c76c46242c911389eb0ab27f2df16eb --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/packages_index_additions.html @@ -0,0 +1,72 @@ + + + + + + + + + +Package Additions Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Packages +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        +
        +
        + +android.appwidget
        +android.inputmethodservice
        +android.speech
        +android.text.format
        +android.view.inputmethod
        + +java.beans
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/packages_index_all.html b/docs/html/sdk/api_diff/3/changes/packages_index_all.html new file mode 100644 index 0000000000000000000000000000000000000000..5876fe92fca9b88b7fe0c9e2069363136bbf7e4a --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/packages_index_all.html @@ -0,0 +1,112 @@ + + + + + + + + + +Package Differences Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +Packages +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        +
        +
        + +android
        +android.app
        +android.appwidget
        +android.content
        +android.content.pm
        +android.content.res
        +android.database
        +android.database.sqlite
        +android.graphics
        +android.graphics.drawable
        +android.graphics.drawable.shapes
        +android.hardware
        +android.inputmethodservice
        +android.location
        +android.media
        +android.net
        +android.net.wifi
        +android.opengl
        +android.os
        +android.preference
        +android.provider
        +android.speech
        +android.telephony
        +android.telephony.gsm
        +android.test
        +android.test.mock
        +android.test.suitebuilder
        +android.text
        +android.text.format
        +android.text.method
        +android.text.style
        +android.util
        +android.view
        +android.view.animation
        +android.view.inputmethod
        +android.webkit
        +android.widget
        + +dalvik.system
        + +java.beans
        +java.lang
        +java.lang.reflect
        +java.net
        +java.util
        +java.util.jar
        +java.util.logging
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/packages_index_changes.html b/docs/html/sdk/api_diff/3/changes/packages_index_changes.html new file mode 100644 index 0000000000000000000000000000000000000000..3665a918f31fff0e8dd51db280a6214026d75528 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/packages_index_changes.html @@ -0,0 +1,106 @@ + + + + + + + + + +Package Changes Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Packages +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        +
        +
        + +android
        +android.app
        +android.content
        +android.content.pm
        +android.content.res
        +android.database
        +android.database.sqlite
        +android.graphics
        +android.graphics.drawable
        +android.graphics.drawable.shapes
        +android.hardware
        +android.location
        +android.media
        +android.net
        +android.net.wifi
        +android.opengl
        +android.os
        +android.preference
        +android.provider
        +android.telephony
        +android.telephony.gsm
        +android.test
        +android.test.mock
        +android.test.suitebuilder
        +android.text
        +android.text.method
        +android.text.style
        +android.util
        +android.view
        +android.view.animation
        +android.webkit
        +android.widget
        + +dalvik.system
        + +java.lang
        +java.lang.reflect
        +java.net
        +java.util
        +java.util.jar
        +java.util.logging
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/packages_index_removals.html b/docs/html/sdk/api_diff/3/changes/packages_index_removals.html new file mode 100644 index 0000000000000000000000000000000000000000..17a90d9989ca7044f0fbe80b89e03d35ebe383d7 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/packages_index_removals.html @@ -0,0 +1,64 @@ + + + + + + + + + +Package Removals Index + + + + + + + + + + + + + + + +
        + Filter the Index: +
        +All Packages +
        +Removals +
        +Additions +
        +Changes +
        +
        +Bold indicates New; Strike indicates deleted. Plain indicates changed. +
        +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.app.html b/docs/html/sdk/api_diff/3/changes/pkg_android.app.html new file mode 100644 index 0000000000000000000000000000000000000000..c1602d80f1a3adaa759a7df51e5049f7bae6111f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.app.html @@ -0,0 +1,198 @@ + + + + + + + + + +android.app + + + + + + + + + + +
        +
        +
        +

        +Package android.app +

        +

        + + + + + + + + + + + + + + + + + + + + +
        Added Classes +
        + + ActivityManager.RunningAppProcessInfo +  
        + + IntentService +  
        + + LauncherActivity.IconResizer +  
        + + LauncherActivity.ListItem +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + Activity +  
        + + ActivityManager +  
        + + AlarmManager +  
        + + AlertDialog +  
        + + Instrumentation +  
        + + LauncherActivity +  
        + + PendingIntent +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.content.html b/docs/html/sdk/api_diff/3/changes/pkg_android.content.html new file mode 100644 index 0000000000000000000000000000000000000000..8a9f4af0a243aa557e457ef3aa6c87b392b77612 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.content.html @@ -0,0 +1,155 @@ + + + + + + + + + +android.content + + + + + + + + + + +
        +
        +
        +

        +Package android.content +

        +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + BroadcastReceiver +  
        + + ContentProvider +  
        + + ContentResolver +  
        + + Context +  
        + + DialogInterface +  
        + + Intent +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.content.pm.html b/docs/html/sdk/api_diff/3/changes/pkg_android.content.pm.html new file mode 100644 index 0000000000000000000000000000000000000000..d3bddd4badc3bcfc9eb28740553476ab7d409db9 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.content.pm.html @@ -0,0 +1,149 @@ + + + + + + + + + +android.content.pm + + + + + + + + + + +
        +
        +
        +

        +Package android.content.pm +

        +

        + + + + + + + + +
        Added Classes +
        + + ConfigurationInfo +  
        +  +

        + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + ActivityInfo +  
        + + PackageInfo +  
        + + PackageManager +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.content.res.html b/docs/html/sdk/api_diff/3/changes/pkg_android.content.res.html new file mode 100644 index 0000000000000000000000000000000000000000..81d234d2263c22184c4db38b5a2429951d68bc58 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.content.res.html @@ -0,0 +1,163 @@ + + + + + + + + + +android.content.res + + + + + + + + + + +
        +
        +
        +

        +Package android.content.res +

        +

        + + + + + + + + + + + + +
        Added Classes +
        + + AssetFileDescriptor.AutoCloseInputStream +  
        + + AssetFileDescriptor.AutoCloseOutputStream +  
        +  +

        + + + + + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + AssetFileDescriptor +  
        + + Configuration +  
        + + Resources +  
        + + TypedArray +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.database.html b/docs/html/sdk/api_diff/3/changes/pkg_android.database.html new file mode 100644 index 0000000000000000000000000000000000000000..70b964445d554a4589d75b1dd8a7dc5040e51ead --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.database.html @@ -0,0 +1,134 @@ + + + + + + + + + +android.database + + + + + + + + + + +
        +
        +
        +

        +Package android.database +

        +

        + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + Cursor +  
        + + CursorWrapper +  
        + + DatabaseUtils +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.database.sqlite.html b/docs/html/sdk/api_diff/3/changes/pkg_android.database.sqlite.html new file mode 100644 index 0000000000000000000000000000000000000000..db2017bbdc9b49dea67bc4f28df8df42b4dab143 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.database.sqlite.html @@ -0,0 +1,120 @@ + + + + + + + + + +android.database.sqlite + + + + + + + + + + +
        +
        +
        +

        +Package android.database.sqlite +

        +

        + + + + + + + + +
        Changed Classes +
        + + SQLiteDatabase +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.drawable.html b/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.drawable.html new file mode 100644 index 0000000000000000000000000000000000000000..6025b71b03d862285efd2141774bb3f12ac90601 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.drawable.html @@ -0,0 +1,141 @@ + + + + + + + + + +android.graphics.drawable + + + + + + + + + + +
        +
        +
        +

        +Package android.graphics.drawable +

        +

        + + + + + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + Drawable +  
        + + RotateDrawable +  
        + + ScaleDrawable +  
        + + TransitionDrawable +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.drawable.shapes.html b/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.drawable.shapes.html new file mode 100644 index 0000000000000000000000000000000000000000..affdaabc6321c4863997727999962e4f82bee380 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.drawable.shapes.html @@ -0,0 +1,120 @@ + + + + + + + + + +android.graphics.drawable.shapes + + + + + + + + + + +
        +
        +
        +

        +Package android.graphics.drawable.shapes +

        +

        + + + + + + + + +
        Changed Classes +
        + + Shape +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.html b/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.html new file mode 100644 index 0000000000000000000000000000000000000000..c7644d5860bd082fa87e968e7eb9c9c82688388c --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.graphics.html @@ -0,0 +1,141 @@ + + + + + + + + + +android.graphics + + + + + + + + + + +
        +
        +
        +

        +Package android.graphics +

        +

        + + + + + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + Bitmap +  
        + + Canvas +  
        + + Rect +  
        + + RectF +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.hardware.html b/docs/html/sdk/api_diff/3/changes/pkg_android.hardware.html new file mode 100644 index 0000000000000000000000000000000000000000..63ebbdc19f69199324f7141348e1202d01642828 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.hardware.html @@ -0,0 +1,170 @@ + + + + + + + + + +android.hardware + + + + + + + + + + +
        +
        +
        +

        +Package android.hardware +

        +

        + + + + + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + GeomagneticField +  
        + + Sensor +  
        + + SensorEvent +  
        + + SensorEventListener +  
        +  +

        + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + Camera +  
        + + SensorListener +  
        + + SensorManager +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.html b/docs/html/sdk/api_diff/3/changes/pkg_android.html new file mode 100644 index 0000000000000000000000000000000000000000..0cedd98cb86e8839d28d3469829ff968ac508dd9 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.html @@ -0,0 +1,177 @@ + + + + + + + + + +android + + + + + + + + + + +
        +
        +
        +

        +Package android +

        +

        + + + + + + + + + + + + +
        Added Classes +
        + + R.bool +  
        + + R.integer +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + Manifest.permission +  
        + + R.attr +  
        + + R.drawable +  
        + + R.id +  
        + + R.string +  
        + + R.style +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.location.html b/docs/html/sdk/api_diff/3/changes/pkg_android.location.html new file mode 100644 index 0000000000000000000000000000000000000000..2f8af381b95d9011f29f565896266c16e227f75e --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.location.html @@ -0,0 +1,156 @@ + + + + + + + + + +android.location + + + + + + + + + + +
        +
        +
        +

        +Package android.location +

        +

        + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + GpsSatellite +  
        + + GpsStatus +  
        + + GpsStatus.Listener +  
        +  +

        + + + + + + + + + + + + +
        Changed Classes +
        + + Location +  
        + + LocationManager +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.media.html b/docs/html/sdk/api_diff/3/changes/pkg_android.media.html new file mode 100644 index 0000000000000000000000000000000000000000..c531240beb8d1a2898ccc9c6df3aaa56b8ad78cf --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.media.html @@ -0,0 +1,254 @@ + + + + + + + + + +android.media + + + + + + + + + + +
        +
        +
        +

        +Package android.media +

        +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + AudioFormat +  
        + + AudioRecord +  
        + + AudioRecord.OnRecordPositionUpdateListener +  
        + + AudioTrack +  
        + + AudioTrack.OnPlaybackPositionUpdateListener +  
        + + JetPlayer +  
        + + JetPlayer.OnJetEventListener +  
        + + MediaPlayer.OnInfoListener +  
        + + MediaPlayer.OnVideoSizeChangedListener +  
        + + MediaRecorder.OnErrorListener +  
        + + MediaRecorder.OnInfoListener +  
        + + MediaRecorder.VideoEncoder +  
        + + MediaRecorder.VideoSource +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + AudioManager +  
        + + MediaPlayer +  
        + + MediaRecorder +  
        + + MediaRecorder.OutputFormat +  
        + + RingtoneManager +  
        + + SoundPool +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.net.html b/docs/html/sdk/api_diff/3/changes/pkg_android.net.html new file mode 100644 index 0000000000000000000000000000000000000000..cf2f916cede7b83ce641d684cdcb1646009e5599 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.net.html @@ -0,0 +1,127 @@ + + + + + + + + + +android.net + + + + + + + + + + +
        +
        +
        +

        +Package android.net +

        +

        + + + + + + + + + + + + +
        Changed Classes +
        + + ConnectivityManager +  
        + + NetworkInfo +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.net.wifi.html b/docs/html/sdk/api_diff/3/changes/pkg_android.net.wifi.html new file mode 100644 index 0000000000000000000000000000000000000000..99f2951d1f7888eb150fe126685f5e1ad0e6f394 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.net.wifi.html @@ -0,0 +1,120 @@ + + + + + + + + + +android.net.wifi + + + + + + + + + + +
        +
        +
        +

        +Package android.net.wifi +

        +

        + + + + + + + + +
        Changed Classes +
        + + WifiManager +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.opengl.html b/docs/html/sdk/api_diff/3/changes/pkg_android.opengl.html new file mode 100644 index 0000000000000000000000000000000000000000..622d8612fb9788a698054d2231fa84163123b0a4 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.opengl.html @@ -0,0 +1,148 @@ + + + + + + + + + +android.opengl + + + + + + + + + + +
        +
        +
        +

        +Package android.opengl +

        +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + GLSurfaceView +  
        + + GLSurfaceView.EGLConfigChooser +  
        + + GLSurfaceView.GLWrapper +  
        + + GLSurfaceView.Renderer +  
        + + Visibility +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.os.html b/docs/html/sdk/api_diff/3/changes/pkg_android.os.html new file mode 100644 index 0000000000000000000000000000000000000000..098864ef879d87e9ff0098bacccbc379cdfcc295 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.os.html @@ -0,0 +1,212 @@ + + + + + + + + + +android.os + + + + + + + + + + +
        +
        +
        +

        +Package android.os +

        +

        + + + + + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + AsyncTask +  
        + + AsyncTask.Status +  
        + + Handler.Callback +  
        + + ResultReceiver +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + Binder +  
        + + Build +  
        + + Debug +  
        + + Environment +  
        + + Handler +  
        + + IBinder +  
        + + Looper +  
        + + Parcel +  
        + + ParcelFileDescriptor +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.preference.html b/docs/html/sdk/api_diff/3/changes/pkg_android.preference.html new file mode 100644 index 0000000000000000000000000000000000000000..5ffe3cb61f34b8a85cdf3dce34781a51d414b466 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.preference.html @@ -0,0 +1,120 @@ + + + + + + + + + +android.preference + + + + + + + + + + +
        +
        +
        +

        +Package android.preference +

        +

        + + + + + + + + +
        Changed Classes +
        + + DialogPreference +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.provider.html b/docs/html/sdk/api_diff/3/changes/pkg_android.provider.html new file mode 100644 index 0000000000000000000000000000000000000000..f16e4fd197677dce565c8946c83e24b1b5f5c9d6 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.provider.html @@ -0,0 +1,233 @@ + + + + + + + + + +android.provider + + + + + + + + + + +
        +
        +
        +

        +Package android.provider +

        +

        + + + + + + + + + + + + + + + + + + + + +
        Added Classes +
        + + LiveFolders +  
        + + Settings.Secure +  
        + + UserDictionary +  
        + + UserDictionary.Words +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + Browser +  
        + + Contacts.Intents +  
        + + Contacts.Intents.Insert +  
        + + Contacts.PeopleColumns +  
        + + MediaStore +  
        + + MediaStore.Audio.AlbumColumns +  
        + + MediaStore.Audio.Media +  
        + + MediaStore.Images.Media +  
        + + MediaStore.Video +  
        + + MediaStore.Video.VideoColumns +  
        + + Settings +  
        + + Settings.System +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.telephony.gsm.html b/docs/html/sdk/api_diff/3/changes/pkg_android.telephony.gsm.html new file mode 100644 index 0000000000000000000000000000000000000000..d17223483e027cc5d7f99d232221275730add617 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.telephony.gsm.html @@ -0,0 +1,120 @@ + + + + + + + + + +android.telephony.gsm + + + + + + + + + + +
        +
        +
        +

        +Package android.telephony.gsm +

        +

        + + + + + + + + +
        Changed Classes +
        + + SmsMessage +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.telephony.html b/docs/html/sdk/api_diff/3/changes/pkg_android.telephony.html new file mode 100644 index 0000000000000000000000000000000000000000..8131269eab826dd34364db6d64eef51d6aebf3e8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.telephony.html @@ -0,0 +1,142 @@ + + + + + + + + + +android.telephony + + + + + + + + + + +
        +
        +
        +

        +Package android.telephony +

        +

        + + + + + + + + +
        Added Classes +
        + + NeighboringCellInfo +  
        +  +

        + + + + + + + + + + + + +
        Changed Classes +
        + + PhoneNumberUtils +  
        + + TelephonyManager +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.test.html b/docs/html/sdk/api_diff/3/changes/pkg_android.test.html new file mode 100644 index 0000000000000000000000000000000000000000..3b5edd42df00b12e45e03b2252caff3b9743d9ee --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.test.html @@ -0,0 +1,163 @@ + + + + + + + + + +android.test + + + + + + + + + + +
        +
        +
        +

        +Package android.test +

        +

        + + + + + + + + + + + + +
        Added Classes +
        + + ActivityInstrumentationTestCase2 +  
        + + ProviderTestCase2 +  
        +  +

        + + + + + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + ActivityInstrumentationTestCase +  
        + + InstrumentationTestCase +  
        + + ProviderTestCase +  
        + + TouchUtils +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.test.mock.html b/docs/html/sdk/api_diff/3/changes/pkg_android.test.mock.html new file mode 100644 index 0000000000000000000000000000000000000000..87a371cd22b18f778d70349d0aae5036c97ceae6 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.test.mock.html @@ -0,0 +1,120 @@ + + + + + + + + + +android.test.mock + + + + + + + + + + +
        +
        +
        +

        +Package android.test.mock +

        +

        + + + + + + + + +
        Changed Classes +
        + + MockPackageManager +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.test.suitebuilder.html b/docs/html/sdk/api_diff/3/changes/pkg_android.test.suitebuilder.html new file mode 100644 index 0000000000000000000000000000000000000000..469db289da9236874a33db282b417abe5389d345 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.test.suitebuilder.html @@ -0,0 +1,127 @@ + + + + + + + + + +android.test.suitebuilder + + + + + + + + + + +
        +
        +
        +

        +Package android.test.suitebuilder +

        +

        + + + + + + + + + + + + +
        Changed Classes +
        + + TestMethod +  
        + + TestSuiteBuilder +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.text.html b/docs/html/sdk/api_diff/3/changes/pkg_android.text.html new file mode 100644 index 0000000000000000000000000000000000000000..ffc696676f160f18724e6642fe2c1123989b30a5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.text.html @@ -0,0 +1,191 @@ + + + + + + + + + +android.text + + + + + + + + + + +
        +
        +
        +

        +Package android.text +

        +

        + + + + + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + InputType +  
        + + NoCopySpan +  
        + + NoCopySpan.Concrete +  
        + + ParcelableSpan +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + Annotation +  
        + + AutoText +  
        + + SpanWatcher +  
        + + Spanned +  
        + + TextUtils +  
        + + TextWatcher +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.text.method.html b/docs/html/sdk/api_diff/3/changes/pkg_android.text.method.html new file mode 100644 index 0000000000000000000000000000000000000000..89b94ad3125bd524ec929528c426b7d9aa44fd11 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.text.method.html @@ -0,0 +1,218 @@ + + + + + + + + + +android.text.method + + + + + + + + + + +
        +
        +
        +

        +Package android.text.method +

        +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + ArrowKeyMovementMethod +  
        + + BaseKeyListener +  
        + + DateKeyListener +  
        + + DateTimeKeyListener +  
        + + DialerKeyListener +  
        + + DigitsKeyListener +  
        + + KeyListener +  
        + + MetaKeyKeyListener +  
        + + MovementMethod +  
        + + MultiTapKeyListener +  
        + + QwertyKeyListener +  
        + + ScrollingMovementMethod +  
        + + TextKeyListener +  
        + + TimeKeyListener +  
        + + Touch +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.text.style.html b/docs/html/sdk/api_diff/3/changes/pkg_android.text.style.html new file mode 100644 index 0000000000000000000000000000000000000000..e1e1fec0b4e9ea1493ac5efa3203d0e0f90c74c4 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.text.style.html @@ -0,0 +1,289 @@ + + + + + + + + + +android.text.style + + + + + + + + + + +
        +
        +
        +

        +Package android.text.style +

        +

        + + + + + + + + +
        Added Interfaces +
        + + UpdateAppearance +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + AbsoluteSizeSpan +  
        + + AlignmentSpan.Standard +  
        + + BackgroundColorSpan +  
        + + BulletSpan +  
        + + ClickableSpan +  
        + + DynamicDrawableSpan +  
        + + ForegroundColorSpan +  
        + + ImageSpan +  
        + + LeadingMarginSpan.Standard +  
        + + MaskFilterSpan +  
        + + QuoteSpan +  
        + + RasterizerSpan +  
        + + RelativeSizeSpan +  
        + + ScaleXSpan +  
        + + StrikethroughSpan +  
        + + StyleSpan +  
        + + SubscriptSpan +  
        + + SuperscriptSpan +  
        + + TextAppearanceSpan +  
        + + TypefaceSpan +  
        + + URLSpan +  
        + + UnderlineSpan +  
        + + UpdateLayout +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.util.html b/docs/html/sdk/api_diff/3/changes/pkg_android.util.html new file mode 100644 index 0000000000000000000000000000000000000000..7403be48c31e01d53036ca1be3d9d1ca576351c5 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.util.html @@ -0,0 +1,142 @@ + + + + + + + + + +android.util + + + + + + + + + + +
        +
        +
        +

        +Package android.util +

        +

        + + + + + + + + +
        Added Classes +
        + + PrintStreamPrinter +  
        +  +

        + + + + + + + + + + + + +
        Changed Classes +
        + + SparseIntArray +  
        + + TimeUtils +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.view.animation.html b/docs/html/sdk/api_diff/3/changes/pkg_android.view.animation.html new file mode 100644 index 0000000000000000000000000000000000000000..30c1badc27d7227b377dadbfb7317be9ce9cdfa8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.view.animation.html @@ -0,0 +1,127 @@ + + + + + + + + + +android.view.animation + + + + + + + + + + +
        +
        +
        +

        +Package android.view.animation +

        +

        + + + + + + + + + + + + +
        Changed Classes +
        + + Animation +  
        + + Transformation +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.view.html b/docs/html/sdk/api_diff/3/changes/pkg_android.view.html new file mode 100644 index 0000000000000000000000000000000000000000..9b4a0427dacdeaecc66d3aecf9dae013a168ad02 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.view.html @@ -0,0 +1,268 @@ + + + + + + + + + +android.view + + + + + + + + + + +
        +
        +
        +

        +Package android.view +

        +

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + GestureDetector.OnDoubleTapListener +  
        + + HapticFeedbackConstants +  
        + + OrientationEventListener +  
        + + ViewDebug.CapturedViewProperty +  
        + + ViewTreeObserver.OnScrollChangedListener +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + GestureDetector +  
        + + GestureDetector.SimpleOnGestureListener +  
        + + Gravity +  
        + + KeyCharacterMap +  
        + + KeyEvent +  
        + + Menu +  
        + + MotionEvent +  
        + + OrientationListener +  
        + + View +  
        + + ViewConfiguration +  
        + + ViewDebug +  
        + + ViewGroup +  
        + + ViewParent +  
        + + ViewTreeObserver +  
        + + Window +  
        + + WindowManager.LayoutParams +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.webkit.html b/docs/html/sdk/api_diff/3/changes/pkg_android.webkit.html new file mode 100644 index 0000000000000000000000000000000000000000..339b9ab3b4794804b7cdedea83a299cc6f3367bd --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.webkit.html @@ -0,0 +1,170 @@ + + + + + + + + + +android.webkit + + + + + + + + + + +
        +
        +
        +

        +Package android.webkit +

        +

        + + + + + + + + +
        Added Classes +
        + + PluginData +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + URLUtil +  
        + + UrlInterceptHandler +  
        + + UrlInterceptRegistry +  
        + + WebHistoryItem +  
        + + WebSettings +  
        + + WebView +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_android.widget.html b/docs/html/sdk/api_diff/3/changes/pkg_android.widget.html new file mode 100644 index 0000000000000000000000000000000000000000..fc6e9015391a693b6e3346d8ebad4ca89ae5d9f8 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_android.widget.html @@ -0,0 +1,310 @@ + + + + + + + + + +android.widget + + + + + + + + + + +
        +
        +
        +

        +Package android.widget +

        +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Added Classes and Interfaces +
        + + AlphabetIndexer +  
        + + Chronometer.OnChronometerTickListener +  
        + + HorizontalScrollView +  
        + + SectionIndexer +  
        + + SlidingDrawer +  
        + + SlidingDrawer.OnDrawerCloseListener +  
        + + SlidingDrawer.OnDrawerOpenListener +  
        + + SlidingDrawer.OnDrawerScrollListener +  
        + + TextView.OnEditorActionListener +  
        +  +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Changed Classes and Interfaces +
        + + AbsListView +  
        + + AbsSeekBar +  
        + + AbsoluteLayout +  
        + + ArrayAdapter +  
        + + AutoCompleteTextView +  
        + + Chronometer +  
        + + CursorAdapter +  
        + + GridView +  
        + + ListView +  
        + + PopupWindow +  
        + + PopupWindow.OnDismissListener +  
        + + ProgressBar +  
        + + RemoteViews +  
        + + RemoteViews.ActionException +  
        + + ResourceCursorAdapter +  
        + + Scroller +  
        + + SimpleCursorAdapter +  
        + + TextView +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_dalvik.system.html b/docs/html/sdk/api_diff/3/changes/pkg_dalvik.system.html new file mode 100644 index 0000000000000000000000000000000000000000..654be0fb246ea4727bc8e7f79b29b9298c5061d3 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_dalvik.system.html @@ -0,0 +1,149 @@ + + + + + + + + + +dalvik.system + + + + + + + + + + +
        +
        +
        +

        +Package dalvik.system +

        +

        + + + + + + + + +
        Added Classes +
        + + DexClassLoader +  
        +  +

        + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + DexFile +  
        + + VMDebug +  
        + + Zygote +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_java.lang.html b/docs/html/sdk/api_diff/3/changes/pkg_java.lang.html new file mode 100644 index 0000000000000000000000000000000000000000..d7699273d2631e785f007ed74a34af20a38c9c51 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_java.lang.html @@ -0,0 +1,134 @@ + + + + + + + + + +java.lang + + + + + + + + + + +
        +
        +
        +

        +Package java.lang +

        +

        + + + + + + + + + + + + + + + + +
        Changed Classes +
        + + Character.UnicodeBlock +  
        + + Class +  
        + + String +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_java.lang.reflect.html b/docs/html/sdk/api_diff/3/changes/pkg_java.lang.reflect.html new file mode 100644 index 0000000000000000000000000000000000000000..ccc643dd8c998d1c4f97a38c30fd6aa13600257b --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_java.lang.reflect.html @@ -0,0 +1,120 @@ + + + + + + + + + +java.lang.reflect + + + + + + + + + + +
        +
        +
        +

        +Package java.lang.reflect +

        +

        + + + + + + + + +
        Changed Classes +
        + + Proxy +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_java.net.html b/docs/html/sdk/api_diff/3/changes/pkg_java.net.html new file mode 100644 index 0000000000000000000000000000000000000000..98cc83d2cd89c2d16a26a4771c0c25f69a60e546 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_java.net.html @@ -0,0 +1,120 @@ + + + + + + + + + +java.net + + + + + + + + + + +
        +
        +
        +

        +Package java.net +

        +

        + + + + + + + + +
        Changed Classes +
        + + Socket +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_java.util.html b/docs/html/sdk/api_diff/3/changes/pkg_java.util.html new file mode 100644 index 0000000000000000000000000000000000000000..462c73b083b6b4d637c6c24553f606b218731a36 --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_java.util.html @@ -0,0 +1,120 @@ + + + + + + + + + +java.util + + + + + + + + + + +
        +
        +
        +

        +Package java.util +

        +

        + + + + + + + + +
        Changed Classes +
        + + Date +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_java.util.jar.html b/docs/html/sdk/api_diff/3/changes/pkg_java.util.jar.html new file mode 100644 index 0000000000000000000000000000000000000000..f1ac6e5d7f7d017fcbb3b17caf9ab90aa1fa36be --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_java.util.jar.html @@ -0,0 +1,127 @@ + + + + + + + + + +java.util.jar + + + + + + + + + + +
        +
        +
        +

        +Package java.util.jar +

        +

        + + + + + + + + + + + + +
        Changed Interfaces +
        + + Pack200.Packer +  
        + + Pack200.Unpacker +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/changes/pkg_java.util.logging.html b/docs/html/sdk/api_diff/3/changes/pkg_java.util.logging.html new file mode 100644 index 0000000000000000000000000000000000000000..f2cc23d8472e79d63bf63591792dccb659905f7f --- /dev/null +++ b/docs/html/sdk/api_diff/3/changes/pkg_java.util.logging.html @@ -0,0 +1,127 @@ + + + + + + + + + +java.util.logging + + + + + + + + + + +
        +
        +
        +

        +Package java.util.logging +

        +

        + + + + + + + + + + + + +
        Changed Classes +
        + + Level +  
        + + LogManager +  
        +  +

        + +
        +
        + + + + diff --git a/docs/html/sdk/api_diff/3/stylesheet-jdiff.css b/docs/html/sdk/api_diff/3/stylesheet-jdiff.css new file mode 100644 index 0000000000000000000000000000000000000000..b3c1b9af86b9afa4abbf4175b0ae3155140fd281 --- /dev/null +++ b/docs/html/sdk/api_diff/3/stylesheet-jdiff.css @@ -0,0 +1,37 @@ + +/* (http://www.jdiff.org) */ + +div.and-diff-id {border: 1px solid #eee;position:relative;float:right;clear:both;padding:0px;} +table.diffspectable {border:1px;padding:0px;margin:0px;} +.diffspechead {background-color:#eee;} +.diffspectable tr {border:0px;padding:0px;} +.diffspectable td {background-color:eee;border:0px;font-size:90%;font-weight:normal;padding:0px;padding-left:1px;padding-right:1px;text-align:center;color:777;} +td.diffvalueold {color:orange;background-color:white;border:0px;font-size:80%;font-style:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;} +td.diffvaluenew {color:green;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;} +td.diffvalue {color:444;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;} +td.diffspec {background-color:white;border:0px;font-size:80%;font-weight:normal;padding:1px;color:444;text-align:right;padding-right:.5em;line-height:.95em;} +tt {font-size:11pt;font-family:monospace;} +.indexHeader { + font-size:96%; + line-height:.8em;} +.jdiffIndex td { + font-size:96%; + xline-height:.8em; + padding:2px; + padding-left:1em;} +.indexText { + font-size:100%; + padding-left:1em;} +#indexTableCaption { + font-size:96%; + margin-top:.25em; + margin-bottom:0; + } +.hiddenlink { + font-size:96%; + line-height:.8em; + text-decoration:none;} +a { + text-decoration:none;} +a:hover { + text-decoration:underline;} diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd index 3c4f06b5685845a7c9eddd74a08ff3ef3e3df2be..1712ae62128703ad9d4ca3a88928f9522362e37a 100644 --- a/docs/html/sdk/download.jd +++ b/docs/html/sdk/download.jd @@ -3,7 +3,7 @@ hide_license_footer=true @jd:body - +
        +
        + + + +
        + + + + +
        + +
        + + + + + + + + + diff --git a/docs/html/sdk/preview/index.jd b/docs/html/sdk/preview/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..cb699e9121d1dc6f7fc477a6e5897a8f1c912190 --- /dev/null +++ b/docs/html/sdk/preview/index.jd @@ -0,0 +1,5 @@ +sdk.redirect=true +@jd:body + + + diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index 8c7a0a764fe65db63e0fe3c0f323418cefc7a4d7..4b55b56177ce1ca91691bb277b6644396f4e12a8 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -2,17 +2,17 @@
        • -

          Android 1.5 SDK, r1

          Android SDK, r

          Current SDK Release

        • -

          Android System Images

          +

          System Image Version Notes

        • +
        • +

          Native Development Tools

          + +
        • Previous SDK Releases

        • In addition to simple drawing, Drawable provides a number of generic * mechanisms for its client to interact with what is being drawn: - * + * *
            *
          • The {@link #setBounds} method must be called to tell the * Drawable where it is drawn and how large it should be. All Drawables * should respect the requested size, often simply by scaling their * imagery. A client can find the preferred size for some Drawables with * the {@link #getIntrinsicHeight} and {@link #getIntrinsicWidth} methods. - * + * *
          • The {@link #getPadding} method can return from some Drawables * information about how to frame content that is placed inside of them. * For example, a Drawable that is intended to be the frame for a button * widget would need to return padding that correctly places the label * inside of itself. - * + * *
          • The {@link #setState} method allows the client to tell the Drawable * in which state it is to be drawn, such as "focused", "selected", etc. * Some drawables may modify their imagery based on the selected state. - * + * *
          • The {@link #setLevel} method allows the client to supply a single * continuous controller that can modify the Drawable is displayed, such as * a battery level or progress level. Some drawables may modify their * imagery based on the current level. - * + * *
          • A Drawable can perform animations by calling back to its client * through the {@link Callback} interface. All clients should support this * interface (via {@link #setCallback}) so that animations will work. A @@ -71,7 +71,7 @@ import android.util.TypedValue; * {@link android.view.View#setBackgroundDrawable(Drawable)} and * {@link android.widget.ImageView}. *
          - * + * * Though usually not visible to the application, Drawables may take a variety * of forms: * @@ -96,11 +96,12 @@ import android.util.TypedValue; * and Internationalization. */ public abstract class Drawable { + private static final Rect ZERO_BOUNDS_RECT = new Rect(); private int[] mStateSet = StateSet.WILD_CARD; private int mLevel = 0; private int mChangingConfigurations = 0; - private Rect mBounds = new Rect(); + private Rect mBounds = ZERO_BOUNDS_RECT; /*package*/ Callback mCallback = null; private boolean mVisible = true; @@ -118,14 +119,18 @@ public abstract class Drawable { */ public void setBounds(int left, int top, int right, int bottom) { Rect oldBounds = mBounds; - + + if (oldBounds == ZERO_BOUNDS_RECT) { + oldBounds = mBounds = new Rect(); + } + if (oldBounds.left != left || oldBounds.top != top || oldBounds.right != right || oldBounds.bottom != bottom) { mBounds.set(left, top, right, bottom); onBoundsChange(mBounds); } } - + /** * Specify a bounding rectangle for the Drawable. This is where the drawable * will draw when its draw() method is called. @@ -145,12 +150,12 @@ public abstract class Drawable { public final void copyBounds(Rect bounds) { bounds.set(mBounds); } - + /** * Return a copy of the drawable's bounds in a new Rect. This returns the * same values as getBounds(), but the returned object is guaranteed to not * be changed later by the drawable (i.e. it retains no reference to this - * rect). If the caller already has a Rect allocated, call copyBounds(rect) + * rect). If the caller already has a Rect allocated, call copyBounds(rect). * * @return A copy of the drawable's bounds */ @@ -163,27 +168,37 @@ public abstract class Drawable { * object may be the same object stored in the drawable (though this is not * guaranteed), so if a persistent copy of the bounds is needed, call * copyBounds(rect) instead. + * You should also not change the object returned by this method as it may + * be the same object stored in the drawable. * * @return The bounds of the drawable (which may change later, so caller - * beware). + * beware). DO NOT ALTER the returned object as it may change the + * stored bounds of this drawable. + * + * @see #copyBounds() + * @see #copyBounds(android.graphics.Rect) */ public final Rect getBounds() { + if (mBounds == ZERO_BOUNDS_RECT) { + mBounds = new Rect(); + } + return mBounds; } /** * Set a mask of the configuration parameters for which this drawable * may change, requiring that it be re-created. - * + * * @param configs A mask of the changing configuration parameters, as * defined by {@link android.content.res.Configuration}. - * + * * @see android.content.res.Configuration */ public void setChangingConfigurations(int configs) { mChangingConfigurations = configs; } - + /** * Return a mask of the configuration parameters for which this drawable * mau change, requiring that it be re-created. The default implementation @@ -191,23 +206,23 @@ public abstract class Drawable { * {@link #setChangingConfigurations(int)} or 0 by default. Subclasses * may extend this to or in the changing configurations of any other * drawables they hold. - * + * * @return Returns a mask of the changing configuration parameters, as * defined by {@link android.content.res.Configuration}. - * + * * @see android.content.res.Configuration */ public int getChangingConfigurations() { return mChangingConfigurations; } - + /** * Set to true to have the drawable dither its colors when drawn to a device * with fewer than 8-bits per color component. This can improve the look on * those devices, but can also slow down the drawing a little. */ public void setDither(boolean dither) {} - + /** * Set to true to have the drawable filter its bitmap when scaled or rotated * (for drawables that use bitmaps). If the drawable does not use bitmaps, @@ -229,7 +244,7 @@ public abstract class Drawable { * Called when the drawable needs to be redrawn. A view at this point * should invalidate itself (or at least the part of itself where the * drawable appears). - * + * * @param who The drawable that is requesting the update. */ public void invalidateDrawable(Drawable who); @@ -240,7 +255,7 @@ public abstract class Drawable { * {@link android.os.Handler#postAtTime(Runnable, Object, long)} with * the parameters (what, who, when) to perform the * scheduling. - * + * * @param who The drawable being scheduled. * @param what The action to execute. * @param when The time (in milliseconds) to run. The timebase is @@ -254,7 +269,7 @@ public abstract class Drawable { * generally simply call * {@link android.os.Handler#removeCallbacks(Runnable, Object)} with * the parameters (what, who) to unschedule the drawable. - * + * * @param who The drawable being unscheduled. * @param what The action being unscheduled. */ @@ -264,7 +279,7 @@ public abstract class Drawable { /** * Bind a {@link Callback} object to this Drawable. Required for clients * that want to support animated drawables. - * + * * @param cb The client's Callback implementation. */ public final void setCallback(Callback cb) { @@ -275,7 +290,7 @@ public abstract class Drawable { * Use the current {@link Callback} implementation to have this Drawable * redrawn. Does nothing if there is no Callback attached to the * Drawable. - * + * * @see Callback#invalidateDrawable */ public void invalidateSelf() @@ -289,10 +304,10 @@ public abstract class Drawable { * Use the current {@link Callback} implementation to have this Drawable * scheduled. Does nothing if there is no Callback attached to the * Drawable. - * + * * @param what The action being scheduled. * @param when The time (in milliseconds) to run. - * + * * @see Callback#scheduleDrawable */ public void scheduleSelf(Runnable what, long when) @@ -306,9 +321,9 @@ public abstract class Drawable { * Use the current {@link Callback} implementation to have this Drawable * unscheduled. Does nothing if there is no Callback attached to the * Drawable. - * + * * @param what The runnable that you no longer want called. - * + * * @see Callback#unscheduleDrawable */ public void unscheduleSelf(Runnable what) @@ -323,13 +338,13 @@ public abstract class Drawable { * 255 means fully opaque. */ public abstract void setAlpha(int alpha); - + /** * Specify an optional colorFilter for the drawable. Pass null to remove * any filters. */ public abstract void setColorFilter(ColorFilter cf); - + /** * Specify a color and porterduff mode to be the colorfilter for this * drawable. @@ -337,7 +352,7 @@ public abstract class Drawable { public void setColorFilter(int color, PorterDuff.Mode mode) { setColorFilter(new PorterDuffColorFilter(color, mode)); } - + public void clearColorFilter() { setColorFilter(null); } @@ -346,34 +361,34 @@ public abstract class Drawable { * Indicates whether this view will change its appearance based on state. * Clients can use this to determine whether it is necessary to calculate * their state and call setState. - * + * * @return True if this view changes its appearance based on state, false * otherwise. - * + * * @see #setState(int[]) */ public boolean isStateful() { return false; } - + /** * Specify a set of states for the drawable. These are use-case specific, * so see the relevant documentation. As an example, the background for * widgets like Button understand the following states: * [{@link android.R.attr#state_focused}, * {@link android.R.attr#state_pressed}]. - * + * *

          If the new state you are supplying causes the appearance of the * Drawable to change, then it is responsible for calling * {@link #invalidateSelf} in order to have itself redrawn, and * true will be returned from this function. - * + * *

          Note: The Drawable holds a reference on to stateSet * until a new state array is given to it, so you must not modify this * array during that time.

          - * + * * @param stateSet The new set of states to be displayed. - * + * * @return Returns true if this change in state has caused the appearance * of the Drawable to change (hence requiring an invalidate), otherwise * returns false. @@ -396,7 +411,7 @@ public abstract class Drawable { public int[] getState() { return mStateSet; } - + /** * @return The current drawable that will be used by this drawable. For simple drawables, this * is just the drawable itself. For drawables that change state like @@ -416,9 +431,9 @@ public abstract class Drawable { * Drawable to change, then it is responsible for calling * {@link #invalidateSelf} in order to have itself redrawn, and * true will be returned from this function. - * + * * @param level The new level, from 0 (minimum) to 10000 (maximum). - * + * * @return Returns true if this change in level has caused the appearance * of the Drawable to change (hence requiring an invalidate), otherwise * returns false. @@ -529,7 +544,7 @@ public abstract class Drawable { * region; subclasses can optionally override this to return an actual * Region if they want to supply this optimization information, but it is * not required that they do so. - * + * * @return Returns null if the Drawables has no transparent region to * report, else a Region holding the parts of the Drawable's bounds that * are transparent. @@ -537,11 +552,11 @@ public abstract class Drawable { public Region getTransparentRegion() { return null; } - + /** * Override this in your subclass to change appearance if you recognize the * specified state. - * + * * @return Returns true if the state change has caused the appearance of * the Drawable to change (that is, it needs to be drawn), else false * if it looks the same and there is no need to redraw it since its @@ -577,13 +592,13 @@ public abstract class Drawable { public int getIntrinsicHeight() { return -1; } - + /** * Returns the minimum width suggested by this Drawable. If a View uses this * Drawable as a background, it is suggested that the View use at least this * value for its width. (There will be some scenarios where this will not be * possible.) This value should INCLUDE any padding. - * + * * @return The minimum width suggested by this Drawable. If this Drawable * doesn't have a suggested minimum width, 0 is returned. */ @@ -597,7 +612,7 @@ public abstract class Drawable { * Drawable as a background, it is suggested that the View use at least this * value for its height. (There will be some scenarios where this will not be * possible.) This value should INCLUDE any padding. - * + * * @return The minimum height suggested by this Drawable. If this Drawable * doesn't have a suggested minimum height, 0 is returned. */ @@ -605,7 +620,7 @@ public abstract class Drawable { final int intrinsicHeight = getIntrinsicHeight(); return intrinsicHeight > 0 ? intrinsicHeight : 0; } - + /** * Return in padding the insets suggested by this Drawable for placing * content inside the drawable's bounds. Positive values move toward the @@ -643,7 +658,7 @@ public abstract class Drawable { /** * Create a drawable from an inputstream - * + * * @hide pending API council approval */ public static Drawable createFromResourceStream(Resources res, TypedValue value, diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 29f2a0018f17d4dae44a68b50f5955e6c88f0fda..f8b88d00a8f1e45c5b47e092d7cb3c4f8fc30c68 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -181,7 +181,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public int getOpacity() { - return mDrawableContainerState.getOpacity(); + return mCurrDrawable == null || !mCurrDrawable.isVisible() ? PixelFormat.TRANSPARENT : + mDrawableContainerState.getOpacity(); } public boolean selectDrawable(int idx) @@ -336,13 +337,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return pos; } - public final int getChildCount() - { + public final int getChildCount() { return mNumChildren; } - public final Drawable[] getChildren() - { + public final Drawable[] getChildren() { return mDrawables; } @@ -350,13 +349,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { * all frames in the set (false), or to use the padding value of the frame * being shown (true). Default value is false. */ - public final void setVariablePadding(boolean variable) - { + public final void setVariablePadding(boolean variable) { mVariablePadding = variable; } - public final Rect getConstantPadding() - { + public final Rect getConstantPadding() { if (mVariablePadding) { return null; } @@ -364,11 +361,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mConstantPadding; } - Rect r = new Rect(0, 0, 0, 0); - Rect t = new Rect(); + final Rect r = new Rect(0, 0, 0, 0); + final Rect t = new Rect(); final int N = getChildCount(); - for (int i=0; i r.left) r.left = t.left; if (t.top > r.top) r.top = t.top; if (t.right > r.right) r.right = t.right; @@ -378,18 +376,15 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return (mConstantPadding=r); } - public final void setConstantSize(boolean constant) - { + public final void setConstantSize(boolean constant) { mConstantSize = constant; } - public final boolean isConstantSize() - { + public final boolean isConstantSize() { return mConstantSize; } - public final int getConstantWidth() - { + public final int getConstantWidth() { if (!mComputedConstantSize) { computeConstantSize(); } @@ -397,8 +392,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mConstantWidth; } - public final int getConstantHeight() - { + public final int getConstantHeight() { if (!mComputedConstantSize) { computeConstantSize(); } @@ -406,8 +400,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mConstantHeight; } - public final int getConstantMinimumWidth() - { + public final int getConstantMinimumWidth() { if (!mComputedConstantSize) { computeConstantSize(); } @@ -415,8 +408,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mConstantMinimumWidth; } - public final int getConstantMinimumHeight() - { + public final int getConstantMinimumHeight() { if (!mComputedConstantSize) { computeConstantSize(); } @@ -424,15 +416,15 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mConstantMinimumHeight; } - private void computeConstantSize() - { + private void computeConstantSize() { mComputedConstantSize = true; final int N = getChildCount(); + final Drawable[] drawables = mDrawables; mConstantWidth = mConstantHeight = 0; mConstantMinimumWidth = mConstantMinimumHeight = 0; - for (int i=0; i mConstantWidth) mConstantWidth = s; s = dr.getIntrinsicHeight(); @@ -444,23 +436,22 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } - public final int getOpacity() - { + public final int getOpacity() { if (mHaveOpacity) { return mOpacity; } final int N = getChildCount(); - int op = N > 0 - ? mDrawables[0].getOpacity() : PixelFormat.TRANSPARENT; - for (int i=1; i 0 ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT; + for (int i = 1; i < N; i++) { + op = Drawable.resolveOpacity(op, drawables[i].getOpacity()); } mOpacity = op; mHaveOpacity = true; return op; } - + public final boolean isStateful() { if (mHaveStateful) { return mStateful; @@ -480,8 +471,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return stateful; } - public void growArray(int oldSize, int newSize) - { + public void growArray(int oldSize, int newSize) { Drawable[] newDrawables = new Drawable[newSize]; System.arraycopy(mDrawables, 0, newDrawables, 0, oldSize); mDrawables = newDrawables; diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index 7164b78e07357df75dfdb0c6574d6cd57c7a1023..6aa40d008eba81f7b06a6fd8cffa984aa06b2b17 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -312,7 +312,6 @@ private: bool processAudioBuffer(const sp& thread); - sp mAudioFlinger; sp mAudioRecord; sp mCblkMemory; sp mClientRecordThread; diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 76459786ee0e77614af007faca20454d2fd06965..ba0467c1603c610044f9b108b6d41a79680ab650 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -383,7 +383,6 @@ private: bool processAudioBuffer(const sp& thread); - sp mAudioFlinger; sp mAudioTrack; sp mCblkMemory; sp mAudioTrackThread; diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h index ec64e4d70434749fd34bc60d4bc68a8c8227a288..6b0cc8ab8cceb0fb788f28b9df2b3dea7d3430d9 100644 --- a/include/media/ToneGenerator.h +++ b/include/media/ToneGenerator.h @@ -18,7 +18,7 @@ #define ANDROID_TONEGENERATOR_H_ #include -#include +#include #include #include #include @@ -49,21 +49,30 @@ public: TONE_DTMF_C, // C key: 1633Hz, 852Hz TONE_DTMF_D, // D key: 1633Hz, 941Hz // Call supervisory tones: 3GPP TS 22.001 (CEPT) - TONE_SUP_DIAL, // Dial tone: 425Hz, continuous - TONE_SUP_BUSY, // Busy tone: 425Hz, 500ms ON, 500ms OFF... - TONE_SUP_CONGESTION, // Congestion tone: 425Hz, 200ms ON, 200ms OFF... - TONE_SUP_RADIO_ACK, // Radio path acknowlegment: 425Hz, 200ms ON + TONE_SUP_DIAL, // Dial tone: CEPT: 425Hz, continuous + FIRST_SUP_TONE = TONE_SUP_DIAL, + TONE_SUP_BUSY, // Busy tone, CEPT: 425Hz, 500ms ON, 500ms OFF... + TONE_SUP_CONGESTION, // Congestion tone CEPT, JAPAN: 425Hz, 200ms ON, 200ms OFF... + TONE_SUP_RADIO_ACK, // Radio path acknowlegment, CEPT, ANSI: 425Hz, 200ms ON TONE_SUP_RADIO_NOTAVAIL, // Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts TONE_SUP_ERROR, // Error/Special info: 950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF... - TONE_SUP_CALL_WAITING, // Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF... - TONE_SUP_RINGTONE, // Ring Tone: 425Hz, 1s ON, 4s OFF... + TONE_SUP_CALL_WAITING, // Call Waiting CEPT,JAPAN: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF... + TONE_SUP_RINGTONE, // Ring Tone CEPT, JAPAN: 425Hz, 1s ON, 4s OFF... + LAST_SUP_TONE = TONE_SUP_RINGTONE, // Proprietary tones: 3GPP TS 31.111 TONE_PROP_BEEP, // General beep: 400Hz+1200Hz, 35ms ON TONE_PROP_ACK, // Positive Acknowlgement: 1200Hz, 100ms ON, 100ms OFF 2 bursts - TONE_PROP_NACK, // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON + TONE_PROP_NACK, // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON TONE_PROP_PROMPT, // Prompt tone: 400Hz+1200Hz, 200ms ON TONE_PROP_BEEP2, // General double beep: 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms on - NUM_TONES + // Additional call supervisory tones: specified by IS-95 only + TONE_SUP_INTERCEPT, // Intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms. + TONE_SUP_INTERCEPT_ABBREV, // Abbreviated intercept: intercept tone limited to 4 seconds + TONE_SUP_CONGESTION_ABBREV, // Abbreviated congestion: congestion tone limited to 4 seconds + TONE_SUP_CONFIRM, // Confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle. + TONE_SUP_PIP, // Pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off). + NUM_TONES, + NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1 }; ToneGenerator(int streamType, float volume); @@ -85,13 +94,45 @@ private: TONE_RESTARTING // }; - static const unsigned int TONEGEN_MAX_WAVES = 3; - static const unsigned int TONEGEN_MAX_SEGMENTS = 4; // Maximun number of elenemts in + + // Region specific tones. + // These supervisory tones are different depending on the region (USA/CANADA, JAPAN, rest of the world). + // When a tone in the range [FIRST_SUP_TONE, LAST_SUP_TONE] is requested, the region is determined + // from system property gsm.operator.iso-country and the proper tone descriptor is selected with the + // help of sToneMappingTable[] + enum regional_tone_type { + // ANSI supervisory tones + TONE_ANSI_DIAL = NUM_TONES, // Dial tone: a continuous 350 Hz + 440 Hz tone. + TONE_ANSI_BUSY, // Busy tone on: a 480 Hz + 620 Hz tone repeated in a 500 ms on, 500 ms off cycle. + TONE_ANSI_CONGESTION, // Network congestion (reorder) tone on: a 480 Hz + 620 Hz tone repeated in a 250 ms on, 250 ms off cycle. + TONE_ANSI_CALL_WAITING, // Call waiting tone on: 440 Hz, on for 300 ms, 9,7 s off followed by + // (440 Hz, on for 100 ms off for 100 ms, on for 100 ms, 9,7s off and repeated as necessary). + TONE_ANSI_RINGTONE, // Ring Tone: a 440 Hz + 480 Hz tone repeated in a 2 s on, 4 s off pattern. + // JAPAN Supervisory tones + TONE_JAPAN_DIAL, // Dial tone: 400Hz, continuous + TONE_JAPAN_BUSY, // Busy tone: 400Hz, 500ms ON, 500ms OFF... + TONE_JAPAN_RADIO_ACK, // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF... + NUM_ALTERNATE_TONES + }; + + enum region { + ANSI, + JAPAN, + CEPT, + NUM_REGIONS + }; + + static const unsigned char sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES]; + + static const unsigned int TONEGEN_MAX_WAVES = 3; // Maximun number of sine waves in a tone segment + static const unsigned int TONEGEN_MAX_SEGMENTS = 5; // Maximun number of segments in a tone descriptor static const unsigned int TONEGEN_INF = 0xFFFFFFFF; // Represents infinite time duration static const float TONEGEN_GAIN = 0.9; // Default gain passed to WaveGenerator(). // ToneDescriptor class contains all parameters needed to generate a tone: - // - The array waveFreq[] contains the frequencies of all individual waves making the multi-tone. + // - The array waveFreq[]: + // 1 for static tone descriptors: contains the frequencies of all individual waves making the multi-tone. + // 2 for active tone descritors: contains the indexes of the WaveGenerator objects in mWaveGens // The number of sine waves varies from 1 to TONEGEN_MAX_WAVES. // The first null value indicates that no more waves are needed. // - The array segments[] is used to generate the tone pulses. A segment is a period of time @@ -100,17 +141,25 @@ private: // The data stored in segments[] is the duration of the corresponding period in ms. // The first segment encountered with a 0 duration indicates that no more segment follows. // - repeatCnt indicates the number of times the sequence described by segments[] array must be repeated. - // When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount. - // If mCurCount > repeatCnt, the tone is stopped automatically. + // When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount. + // If mCurCount > repeatCnt, the tone is stopped automatically. Otherwise, tone sequence will be + // restarted from segment repeatSegment. + // - repeatSegment number of the first repeated segment when repeatCnt is not null - class ToneDescriptor { + class ToneSegment { public: + unsigned int duration; unsigned short waveFreq[TONEGEN_MAX_WAVES+1]; - unsigned long segments[TONEGEN_MAX_SEGMENTS+1]; + }; + + class ToneDescriptor { + public: + ToneSegment segments[TONEGEN_MAX_SEGMENTS+1]; unsigned long repeatCnt; + unsigned long repeatSegment; }; - static const ToneDescriptor toneDescriptors[NUM_TONES]; + static const ToneDescriptor sToneDescriptors[]; unsigned int mTotalSmp; // Total number of audio samples played (gives current time) unsigned int mNextSegSmp; // Position of next segment transition expressed in samples @@ -121,6 +170,7 @@ private: unsigned short mCurSegment; // Current segment index in ToneDescriptor segments[] unsigned short mCurCount; // Current sequence repeat count volatile unsigned short mState; // ToneGenerator state (tone_state) + unsigned short mRegion; const ToneDescriptor *mpToneDesc; // pointer to active tone descriptor const ToneDescriptor *mpNewToneDesc; // pointer to next active tone descriptor @@ -136,8 +186,9 @@ private: bool initAudioTrack(); static void audioCallback(int event, void* user, void *info); bool prepareWave(); - unsigned int numWaves(); + unsigned int numWaves(unsigned int segmentIdx); void clearWaveGens(); + int getToneForRegion(int toneType); // WaveGenerator generates a single sine wave class WaveGenerator { @@ -167,7 +218,7 @@ private: short mAmplitude_Q15; // Q15 amplitude }; - Vector mWaveGens; // list of active wave generators. + KeyedVector mWaveGens; // list of active wave generators. }; } diff --git a/include/ui/Camera.h b/include/ui/Camera.h index e593feab7899aa29c1c0267fb369b8d3ec2644e9..048bdd560b0b5aa1d61e07e2767b95618433887e 100644 --- a/include/ui/Camera.h +++ b/include/ui/Camera.h @@ -63,6 +63,23 @@ namespace android { #define FRAME_CALLBACK_FLAG_CAMERA 0x05 #define FRAME_CALLBACK_FLAG_BARCODE_SCANNER 0x07 +// msgType in notifyCallback function +enum { + CAMERA_MSG_ERROR, + CAMERA_MSG_SHUTTER, + CAMERA_MSG_FOCUS, + CAMERA_MSG_ZOOM +}; + +// msgType in dataCallback function +enum { + CAMERA_MSG_PREVIEW_FRAME, + CAMERA_MSG_VIDEO_FRAME, + CAMERA_MSG_POSTVIEW_FRAME, + CAMERA_MSG_RAW_IMAGE, + CAMERA_MSG_COMPRESSED_IMAGE +}; + class ICameraService; class ICamera; class Surface; @@ -78,8 +95,7 @@ class Camera : public BnCameraClient, public IBinder::DeathRecipient { public: // construct a camera client from an existing remote - Camera(const sp& camera); - + static sp create(const sp& camera); static sp connect(); ~Camera(); void init(); @@ -137,13 +153,8 @@ public: void setAutoFocusCallback(autofocus_callback cb, void *cookie); // ICameraClient interface - virtual void shutterCallback(); - virtual void rawCallback(const sp& picture); - virtual void jpegCallback(const sp& picture); - virtual void previewCallback(const sp& frame); - virtual void errorCallback(status_t error); - virtual void autoFocusCallback(bool focused); - virtual void recordingCallback(const sp& frame); + virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2); + virtual void dataCallback(int32_t msgType, const sp& dataPtr); sp remote(); diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h index 73b951cf3cc0e1e15551b173733404166827b73a..c4bdd07585757040e9bfbdeba3c3a78da28c2cec 100644 --- a/include/ui/ICameraClient.h +++ b/include/ui/ICameraClient.h @@ -29,13 +29,8 @@ class ICameraClient: public IInterface public: DECLARE_META_INTERFACE(CameraClient); - virtual void shutterCallback() = 0; - virtual void rawCallback(const sp& picture) = 0; - virtual void jpegCallback(const sp& picture) = 0; - virtual void previewCallback(const sp& frame) = 0; - virtual void errorCallback(status_t error) = 0; - virtual void autoFocusCallback(bool focused) = 0; - virtual void recordingCallback(const sp& frame) = 0; + virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0; + virtual void dataCallback(int32_t msgType, const sp& data) = 0; }; diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index d01d83f831690abe1069a1de4ba43c018fc6c0db..9b8c3026a088f5ae1208e2e731830d411ef52cb3 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -988,119 +988,225 @@ struct ResTable_config return diffs; } - // Return true if 'this' is more specific than 'o'. Optionally, if - // 'requested' is null, then they will also be compared against the - // requested configuration and true will only be returned if 'this' - // is a better candidate than 'o' for the configuration. This assumes that - // match() has already been used to remove any configurations that don't - // match the requested configuration at all; if they are not first filtered, - // non-matching results can be considered better than matching ones. + // Return true if 'this' is more specific than 'o'. inline bool - isBetterThan(const ResTable_config& o, const ResTable_config* requested = NULL) const { + isMoreSpecificThan(const ResTable_config& o) const { // The order of the following tests defines the importance of one // configuration parameter over another. Those tests first are more // important, trumping any values in those following them. - if (imsi != 0 && (!requested || requested->imsi != 0)) { - if (mcc != 0 && (!requested || requested->mcc != 0)) { - if (o.mcc == 0) { - return true; - } + if (imsi || o.imsi) { + if (mcc != o.mcc) { + if (!mcc) return false; + if (!o.mcc) return true; } - if (mnc != 0 && (!requested || requested->mnc != 0)) { - if (o.mnc == 0) { - return true; - } + + if (mnc != o.mnc) { + if (!mnc) return false; + if (!o.mnc) return true; } } - if (locale != 0 && (!requested || requested->locale != 0)) { - if (language[0] != 0 && (!requested || requested->language[0] != 0)) { - if (o.language[0] == 0) { - return true; - } + + if (locale || o.locale) { + if (language[0] != o.language[0]) { + if (!language[0]) return false; + if (!o.language[0]) return true; } - if (country[0] != 0 && (!requested || requested->country[0] != 0)) { - if (o.country[0] == 0) { - return true; - } + + if (country[0] != o.country[0]) { + if (!country[0]) return false; + if (!o.country[0]) return true; } } - if (screenType != 0 && (!requested || requested->screenType != 0)) { - if (orientation != 0 && (!requested || requested->orientation != 0)) { - if (o.orientation == 0) { - return true; - } + + if (screenType || o.screenType) { + if (orientation != o.orientation) { + if (!orientation) return false; + if (!o.orientation) return true; } - if (density != 0 && (!requested || requested->density != 0)) { - if (o.density == 0) { - return true; - } + + // density is never 'more specific' + // as the default just equals 160 + + if (touchscreen != o.touchscreen) { + if (!touchscreen) return false; + if (!o.touchscreen) return true; } - if (touchscreen != 0 && (!requested || requested->touchscreen != 0)) { - if (o.touchscreen == 0) { - return true; - } + } + + if (input || o.input) { + if (inputFlags != o.inputFlags) { + if (!(inputFlags & MASK_KEYSHIDDEN)) return false; + if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true; + } + + if (keyboard != o.keyboard) { + if (!keyboard) return false; + if (!o.keyboard) return true; + } + + if (navigation != o.navigation) { + if (!navigation) return false; + if (!o.navigation) return true; } } - if (input != 0 && (!requested || requested->input != 0)) { - const int keysHidden = inputFlags&MASK_KEYSHIDDEN; - const int reqKeysHidden = requested - ? requested->inputFlags&MASK_KEYSHIDDEN : 0; - if (keysHidden != 0 && reqKeysHidden != 0) { - const int oKeysHidden = o.inputFlags&MASK_KEYSHIDDEN; - //LOGI("isBetterThan keysHidden: cur=%d, given=%d, config=%d\n", - // keysHidden, oKeysHidden, reqKeysHidden); - if (oKeysHidden == 0) { - //LOGI("Better because 0!"); - return true; + + if (screenSize || o.screenSize) { + if (screenWidth != o.screenWidth) { + if (!screenWidth) return false; + if (!o.screenWidth) return true; + } + + if (screenHeight != o.screenHeight) { + if (!screenHeight) return false; + if (!o.screenHeight) return true; + } + } + + if (version || o.version) { + if (sdkVersion != o.sdkVersion) { + if (!sdkVersion) return false; + if (!o.sdkVersion) return true; + } + + if (minorVersion != o.minorVersion) { + if (!minorVersion) return false; + if (!o.minorVersion) return true; + } + } + return false; + } + + // Return true if 'this' is a better match than 'o' for the 'requested' + // configuration. This assumes that match() has already been used to + // remove any configurations that don't match the requested configuration + // at all; if they are not first filtered, non-matching results can be + // considered better than matching ones. + // The general rule per attribute: if the request cares about an attribute + // (it normally does), if the two (this and o) are equal it's a tie. If + // they are not equal then one must be generic because only generic and + // '==requested' will pass the match() call. So if this is not generic, + // it wins. If this IS generic, o wins (return false). + inline bool + isBetterThan(const ResTable_config& o, + const ResTable_config* requested) const { + if (requested) { + if (imsi || o.imsi) { + if ((mcc != o.mcc) && requested->mcc) { + return (mcc); } - // For compatibility, we count KEYSHIDDEN_NO as being - // the same as KEYSHIDDEN_SOFT. Here we disambiguate these - // may making an exact match more specific. - if (keysHidden == reqKeysHidden && oKeysHidden != reqKeysHidden) { - // The current configuration is an exact match, and - // the given one is not, so the current one is better. - //LOGI("Better because other not same!"); - return true; + + if ((mnc != o.mnc) && requested->mnc) { + return (mnc); } } - if (keyboard != 0 && (!requested || requested->keyboard != 0)) { - if (o.keyboard == 0) { - return true; + + if (locale || o.locale) { + if ((language[0] != o.language[0]) && requested->language[0]) { + return (language[0]); } - } - if (navigation != 0 && (!requested || requested->navigation != 0)) { - if (o.navigation == 0) { - return true; + + if ((country[0] != o.country[0]) && requested->country[0]) { + return (country[0]); } } - } - if (screenSize != 0 && (!requested || requested->screenSize != 0)) { - if (screenWidth != 0 && (!requested || requested->screenWidth != 0)) { - if (o.screenWidth == 0) { - return true; + + if (screenType || o.screenType) { + if ((orientation != o.orientation) && requested->orientation) { + return (orientation); + } + + if (density != o.density) { + // density is tough. Any density is potentially useful + // because the system will scale it. Scaling down + // is generally better than scaling up. + // Default density counts as 160dpi (the system default) + // TODO - remove 160 constants + int h = (density?density:160); + int l = (o.density?o.density:160); + bool bImBigger = true; + if (l > h) { + int t = h; + h = l; + l = t; + bImBigger = false; + } + + int reqValue = (requested->density?requested->density:160); + if (reqValue >= h) { + // requested value higher than both l and h, give h + return bImBigger; + } + if (l >= reqValue) { + // requested value lower than both l and h, give l + return !bImBigger; + } + // saying that scaling down is 2x better than up + if (((2 * l) - reqValue) * h > reqValue * reqValue) { + return !bImBigger; + } else { + return bImBigger; + } + } + + if ((touchscreen != o.touchscreen) && requested->touchscreen) { + return (touchscreen); } } - if (screenHeight != 0 && (!requested || requested->screenHeight != 0)) { - if (o.screenHeight == 0) { - return true; + + if (input || o.input) { + const int keysHidden = inputFlags & MASK_KEYSHIDDEN; + const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN; + if (keysHidden != oKeysHidden) { + const int reqKeysHidden = + requested->inputFlags & MASK_KEYSHIDDEN; + if (reqKeysHidden) { + + if (!keysHidden) return false; + if (!oKeysHidden) return true; + // For compatibility, we count KEYSHIDDEN_NO as being + // the same as KEYSHIDDEN_SOFT. Here we disambiguate + // these by making an exact match more specific. + if (reqKeysHidden == keysHidden) return true; + if (reqKeysHidden == oKeysHidden) return false; + } + } + + if ((keyboard != o.keyboard) && requested->keyboard) { + return (keyboard); + } + + if ((navigation != o.navigation) && requested->navigation) { + return (navigation); } } - } - if (version != 0 && (!requested || requested->version != 0)) { - if (sdkVersion != 0 && (!requested || requested->sdkVersion != 0)) { - if (o.sdkVersion == 0) { - return true; + + if (screenSize || o.screenSize) { + if ((screenWidth != o.screenWidth) && requested->screenWidth) { + return (screenWidth); + } + + if ((screenHeight != o.screenHeight) && + requested->screenHeight) { + return (screenHeight); } } - if (minorVersion != 0 && (!requested || requested->minorVersion != 0)) { - if (o.minorVersion == 0) { - return true; + + if (version || o.version) { + if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) { + return (sdkVersion); + } + + if ((minorVersion != o.minorVersion) && + requested->minorVersion) { + return (minorVersion); } } + + return false; } - return false; + return isMoreSpecificThan(o); } - + // Return true if 'this' can be considered a match for the parameters in // 'settings'. // Note this is asymetric. A default piece of data will match every request @@ -1137,8 +1243,7 @@ struct ResTable_config && orientation != settings.orientation) { return false; } - // Density not taken into account, always match, no matter what - // density is specified for the resource + // density always matches - we can scale it. See isBetterThan if (settings.touchscreen != 0 && touchscreen != 0 && touchscreen != settings.touchscreen) { return false; diff --git a/include/utils/backup_helpers.h b/include/utils/backup_helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..137c5f104172f3328c31b2d2914c14696f466a3d --- /dev/null +++ b/include/utils/backup_helpers.h @@ -0,0 +1,15 @@ +#ifndef _UTILS_BACKUP_HELPERS_H +#define _UTILS_BACKUP_HELPERS_H + +int back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, + char const* fileBase, char const* const* files, int fileCount); + +#define TEST_BACKUP_HELPERS 0 + +#if TEST_BACKUP_HELPERS +int backup_helper_test_empty(); +int backup_helper_test_four(); +int backup_helper_test_files(); +#endif + +#endif // _UTILS_BACKUP_HELPERS_H diff --git a/include/utils/threads.h b/include/utils/threads.h index 8d8d46a054d8e3893e6996a4bb8379ca74847169..b3209156bc3f5db182fad1e084df4a68ce72680c 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -79,6 +79,13 @@ enum { ANDROID_PRIORITY_LESS_FAVORABLE = +1, }; +enum { + ANDROID_TGROUP_DEFAULT = 0, + ANDROID_TGROUP_BG_NONINTERACT = 1, + ANDROID_TGROUP_FG_BOOST = 2, + ANDROID_TGROUP_MAX = ANDROID_TGROUP_FG_BOOST, +}; + // Create and run a new thread. extern int androidCreateThread(android_thread_func_t, void *); diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index d11e13a7fb4aa50a774300a0ce6d2aec16430644..b56221fcae4bda45e491119ca9735dd4fa7a8fbb 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -651,27 +651,30 @@ status_t AudioFlinger::setStreamVolume(int stream, float value) return BAD_VALUE; } - mHardwareMixerThread->setStreamVolume(stream, value); -#ifdef WITH_A2DP - mA2dpMixerThread->setStreamVolume(stream, value); -#endif - status_t ret = NO_ERROR; if (stream == AudioSystem::VOICE_CALL || stream == AudioSystem::BLUETOOTH_SCO) { - + float hwValue; if (stream == AudioSystem::VOICE_CALL) { - value = (float)AudioSystem::logToLinear(value)/100.0f; + hwValue = (float)AudioSystem::logToLinear(value)/100.0f; + // offset value to reflect actual hardware volume that never reaches 0 + // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java) + value = 0.01 + 0.99 * value; } else { // (type == AudioSystem::BLUETOOTH_SCO) - value = 1.0f; + hwValue = 1.0f; } AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_VOICE_VOLUME; - ret = mAudioHardware->setVoiceVolume(value); + ret = mAudioHardware->setVoiceVolume(hwValue); mHardwareStatus = AUDIO_HW_IDLE; } + mHardwareMixerThread->setStreamVolume(stream, value); +#ifdef WITH_A2DP + mA2dpMixerThread->setStreamVolume(stream, value); +#endif + return ret; } @@ -709,7 +712,14 @@ float AudioFlinger::streamVolume(int stream) const if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return 0.0f; } - return mHardwareMixerThread->streamVolume(stream); + + float volume = mHardwareMixerThread->streamVolume(stream); + // remove correction applied by setStreamVolume() + if (stream == AudioSystem::VOICE_CALL) { + volume = (volume - 0.01) / 0.99 ; + } + + return volume; } bool AudioFlinger::streamMute(int stream) const @@ -812,17 +822,12 @@ void AudioFlinger::handleForcedSpeakerRoute(int command) if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) { LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER); mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - mAudioHardware->setMasterVolume(0); usleep(mHardwareMixerThread->latency()*1000); mHardwareStatus = AUDIO_HW_SET_ROUTING; mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER); mHardwareStatus = AUDIO_HW_IDLE; // delay track start so that audio hardware has time to siwtch routes usleep(kStartSleepTime); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume()); - mHardwareStatus = AUDIO_HW_IDLE; } mForcedRoute = AudioSystem::ROUTE_SPEAKER; } @@ -1480,18 +1485,6 @@ status_t AudioFlinger::MixerThread::addTrack_l(const sp& track) return status; } -// removeTrack_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::removeTrack_l(wp track, int name) -{ - sp t = track.promote(); - if (t!=NULL && (t->mState <= TrackBase::STOPPED)) { - t->reset(); - deleteTrackName_l(name); - removeActiveTrack_l(track); - mAudioFlinger->mWaitWorkCV.broadcast(); - } -} - // destroyTrack_l() must be called with AudioFlinger::mLock held void AudioFlinger::MixerThread::destroyTrack_l(const sp& track) { @@ -1697,7 +1690,7 @@ void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t // Check validity of returned pointer in case the track control block would have been corrupted. if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || - cblk->channels == 2 && ((unsigned long)bufferStart & 3) ) { + (cblk->channels == 2 && ((unsigned long)bufferStart & 3))) { LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ server %d, serverBase %d, user %d, userBase %d, channels %d", bufferStart, bufferEnd, mBuffer, mBufferEnd, @@ -1733,7 +1726,6 @@ AudioFlinger::MixerThread::Track::~Track() wp weak(this); // never create a strong ref from the dtor Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); mState = TERMINATED; - mMixerThread->removeTrack_l(weak, mName); } void AudioFlinger::MixerThread::Track::destroy() diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index db5cc7444ba3cade29bc73f761aecaaba8e21541..c7ca9ecc10121c127af2592008bf725004aee38c 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -501,7 +501,6 @@ private: MixerThread& operator = (const MixerThread&); status_t addTrack_l(const sp& track); - void removeTrack_l(wp track, int name); void destroyTrack_l(const sp& track); int getTrackName_l(); void deleteTrackName_l(int name); diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp index ac76a19d8435727d424148f8ad0bf6a4bdcac668..cc1bd8ffa22918e1f4ac5e81635f0256e231fedc 100644 --- a/libs/audioflinger/AudioHardwareInterface.cpp +++ b/libs/audioflinger/AudioHardwareInterface.cpp @@ -53,7 +53,7 @@ static const char* routeStrings[] = "EARPIECE ", "SPEAKER ", "BLUETOOTH ", - "HEADSET " + "HEADSET ", "BLUETOOTH_A2DP " }; static const char* routeNone = "NONE"; diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp index eb75f9998b46212873a331253159d97b67773649..7168bf244f71e1f046aa7bb98f5b3d097e2a4b8e 100644 --- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp +++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp @@ -573,7 +573,11 @@ void GPUHardware::binderDied(const wp& who) sp GPUFactory::getGPU() { - return new GPUHardware(); + sp gpu; + if (access("/dev/hw3d", F_OK) == 0) { + gpu = new GPUHardware(); + } + return gpu; } // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index f65d66984d7f541f0e844a48344bfdc795eb548e..96395a883c1366de564c7eda3fb3f556cbe4fe02 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -108,7 +108,7 @@ status_t Layer::setBuffers( Client* client, // we always force a 4-byte aligned bpr. uint32_t alignment = 1; - if (flags & ISurfaceComposer::eGPU) { + if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) { // FIXME: this value should come from the h/w alignment = 8; // FIXME: this is msm7201A specific, as its GPU only supports diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index de64f55fbdc6448865846bd4f6ba2b3ea255e708..167a59b189776647426a763f18b89d5946b46aeb 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -241,6 +241,9 @@ sp SurfaceFlinger::getCblk() const status_t SurfaceFlinger::requestGPU(const sp& callback, gpu_info_t* gpu) { + if (mGPU == 0) + return INVALID_OPERATION; + IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); status_t err = mGPU->request(pid, callback, gpu); @@ -249,6 +252,9 @@ status_t SurfaceFlinger::requestGPU(const sp& callback, status_t SurfaceFlinger::revokeGPU() { + if (mGPU == 0) + return INVALID_OPERATION; + return mGPU->friendlyRevoke(); } @@ -1600,10 +1606,14 @@ status_t SurfaceFlinger::onTransact( } return NO_ERROR; case 1005: // ask GPU revoke - mGPU->friendlyRevoke(); + if (mGPU != 0) { + mGPU->friendlyRevoke(); + } return NO_ERROR; case 1006: // revoke GPU - mGPU->unconditionalRevoke(); + if (mGPU != 0) { + mGPU->unconditionalRevoke(); + } return NO_ERROR; case 1007: // set mFreezeCount mFreezeCount = data.readInt32(); diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp index 0ccd71f0b8446c7407c6c58c28317fbebd448346..238c602e8684a815a90545b3c7fc64668397f530 100644 --- a/libs/surfaceflinger/VRamHeap.cpp +++ b/libs/surfaceflinger/VRamHeap.cpp @@ -98,7 +98,7 @@ sp SurfaceHeapManager::createHeap( } } - if (flags & ISurfaceComposer::eGPU) { + if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) { // FIXME: this is msm7201A specific, where gpu surfaces may not be secure if (!(flags & ISurfaceComposer::eSecure)) { // if GPU doesn't work, we try eHardware diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp index b3cbda14fb06fa11043f39b90f6c8d24df3cebb6..661370040e44c04f48e91ba97479001dee4f8f72 100644 --- a/libs/ui/Camera.cpp +++ b/libs/ui/Camera.cpp @@ -64,15 +64,22 @@ Camera::Camera() init(); } -Camera::Camera(const sp& camera) +// construct a camera client from an existing camera remote +sp Camera::create(const sp& camera) { - init(); - // connect this client to existing camera remote - if (camera->connect(this) == NO_ERROR) { - mStatus = NO_ERROR; - mCamera = camera; - camera->asBinder()->linkToDeath(this); + LOGV("create"); + if (camera == 0) { + LOGE("camera remote is a NULL pointer"); + return 0; + } + + sp c = new Camera(); + if (camera->connect(c) == NO_ERROR) { + c->mStatus = NO_ERROR; + c->mCamera = camera; + camera->asBinder()->linkToDeath(c); } + return c; } void Camera::init() @@ -330,63 +337,65 @@ void Camera::setErrorCallback(error_callback cb, void *cookie) mErrorCallbackCookie = cookie; } -void Camera::autoFocusCallback(bool focused) -{ - LOGV("autoFocusCallback"); - if (mAutoFocusCallback) { - mAutoFocusCallback(focused, mAutoFocusCallbackCookie); - } -} - -void Camera::shutterCallback() -{ - LOGV("shutterCallback"); - if (mShutterCallback) { - mShutterCallback(mShutterCallbackCookie); - } -} - -void Camera::rawCallback(const sp& picture) -{ - LOGV("rawCallback"); - if (mRawCallback) { - mRawCallback(picture, mRawCallbackCookie); - } -} - -// callback from camera service when image is ready -void Camera::jpegCallback(const sp& picture) +// callback from camera service +void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { - LOGV("jpegCallback"); - if (mJpegCallback) { - mJpegCallback(picture, mJpegCallbackCookie); - } -} - -// callback from camera service when preview frame is ready -void Camera::previewCallback(const sp& frame) -{ - LOGV("frameCallback"); - if (mPreviewCallback) { - mPreviewCallback(frame, mPreviewCallbackCookie); - } -} - -// callback from camera service when a recording frame is ready -void Camera::recordingCallback(const sp& frame) -{ - LOGV("recordingCallback"); - if (mRecordingCallback) { - mRecordingCallback(frame, mRecordingCallbackCookie); + switch(msgType) { + case CAMERA_MSG_ERROR: + LOGV("errorCallback"); + if (mErrorCallback) { + mErrorCallback((status_t)ext1, mErrorCallbackCookie); + } + break; + case CAMERA_MSG_FOCUS: + LOGV("autoFocusCallback"); + if (mAutoFocusCallback) { + mAutoFocusCallback((bool)ext1, mAutoFocusCallbackCookie); + } + break; + case CAMERA_MSG_SHUTTER: + LOGV("shutterCallback"); + if (mShutterCallback) { + mShutterCallback(mShutterCallbackCookie); + } + break; + default: + LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2); + break; } } -// callback from camera service when an error occurs in preview or takePicture -void Camera::errorCallback(status_t error) +// callback from camera service when frame or image is ready +void Camera::dataCallback(int32_t msgType, const sp& dataPtr) { - LOGV("errorCallback"); - if (mErrorCallback) { - mErrorCallback(error, mErrorCallbackCookie); + switch(msgType) { + case CAMERA_MSG_PREVIEW_FRAME: + LOGV("previewCallback"); + if (mPreviewCallback) { + mPreviewCallback(dataPtr, mPreviewCallbackCookie); + } + break; + case CAMERA_MSG_VIDEO_FRAME: + LOGV("recordingCallback"); + if (mRecordingCallback) { + mRecordingCallback(dataPtr, mRecordingCallbackCookie); + } + break; + case CAMERA_MSG_RAW_IMAGE: + LOGV("rawCallback"); + if (mRawCallback) { + mRawCallback(dataPtr, mRawCallbackCookie); + } + break; + case CAMERA_MSG_COMPRESSED_IMAGE: + LOGV("jpegCallback"); + if (mJpegCallback) { + mJpegCallback(dataPtr, mJpegCallbackCookie); + } + break; + default: + LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); + break; } } diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp index 4bec9d2ae6c3c84f713e10fef05d6dbe9ab36bb6..c6cf75c5e951d91f4ce5be0f8c84a9f0118d73a6 100644 --- a/libs/ui/ICameraClient.cpp +++ b/libs/ui/ICameraClient.cpp @@ -25,13 +25,8 @@ namespace android { enum { - SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, - RAW_CALLBACK, - JPEG_CALLBACK, - PREVIEW_CALLBACK, - ERROR_CALLBACK, - AUTOFOCUS_CALLBACK, - RECORDING_CALLBACK, + NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, + DATA_CALLBACK, }; class BpCameraClient: public BpInterface @@ -42,74 +37,29 @@ public: { } - // callback to let the app know the shutter has closed, ideal for playing the shutter sound - void shutterCallback() + // generic callback from camera service to app + void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { - LOGV("shutterCallback"); + LOGV("notifyCallback"); Parcel data, reply; data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + data.writeInt32(msgType); + data.writeInt32(ext1); + data.writeInt32(ext2); + remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); } - // callback from camera service to app with picture data - void rawCallback(const sp& picture) + // generic data callback from camera service to app with image data + void dataCallback(int32_t msgType, const sp& imageData) { - LOGV("rawCallback"); + LOGV("dataCallback"); Parcel data, reply; data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(picture->asBinder()); - remote()->transact(RAW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + data.writeInt32(msgType); + data.writeStrongBinder(imageData->asBinder()); + remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); } - // callback from camera service to app with picture data - void jpegCallback(const sp& picture) - { - LOGV("jpegCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(picture->asBinder()); - remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app with preview frame data - void previewCallback(const sp& frame) - { - LOGV("previewCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(frame->asBinder()); - remote()->transact(PREVIEW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app with recording frame data - void recordingCallback(const sp& frame) - { - LOGV("recordingCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(frame->asBinder()); - remote()->transact(RECORDING_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app to report error - void errorCallback(status_t error) - { - LOGV("errorCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeInt32(error); - remote()->transact(ERROR_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app to report autofocus completion - void autoFocusCallback(bool focused) - { - LOGV("autoFocusCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeInt32(focused); - remote()->transact(AUTOFOCUS_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } }; IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient"); @@ -126,52 +76,21 @@ status_t BnCameraClient::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { - case SHUTTER_CALLBACK: { - LOGV("SHUTTER_CALLBACK"); + case NOTIFY_CALLBACK: { + LOGV("NOTIFY_CALLBACK"); CHECK_INTERFACE(ICameraClient, data, reply); - shutterCallback(); + int32_t msgType = data.readInt32(); + int32_t ext1 = data.readInt32(); + int32_t ext2 = data.readInt32(); + notifyCallback(msgType, ext1, ext2); return NO_ERROR; } break; - case RAW_CALLBACK: { + case DATA_CALLBACK: { LOGV("RAW_CALLBACK"); CHECK_INTERFACE(ICameraClient, data, reply); - sp picture = interface_cast(data.readStrongBinder()); - rawCallback(picture); - return NO_ERROR; - } break; - case JPEG_CALLBACK: { - LOGV("JPEG_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - sp picture = interface_cast(data.readStrongBinder()); - jpegCallback(picture); - return NO_ERROR; - } break; - case PREVIEW_CALLBACK: { - LOGV("PREVIEW_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - sp frame = interface_cast(data.readStrongBinder()); - previewCallback(frame); - return NO_ERROR; - } break; - case RECORDING_CALLBACK: { - LOGV("RECORDING_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - sp frame = interface_cast(data.readStrongBinder()); - recordingCallback(frame); - return NO_ERROR; - } break; - case ERROR_CALLBACK: { - LOGV("ERROR_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - status_t error = data.readInt32(); - errorCallback(error); - return NO_ERROR; - } break; - case AUTOFOCUS_CALLBACK: { - LOGV("AUTOFOCUS_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - bool focused = (bool)data.readInt32(); - autoFocusCallback(focused); + int32_t msgType = data.readInt32(); + sp imageData = interface_cast(data.readStrongBinder()); + dataCallback(msgType, imageData); return NO_ERROR; } break; default: diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index cdb8ca2d70bcd9d6a8b64edefbe5b0c2381311bb..f9fb780388bc3de029c3766f81c95c5e8bfcc5f2 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -116,7 +116,8 @@ LOCAL_SRC_FILES:= \ ProcessState.cpp \ IPermissionController.cpp \ IServiceManager.cpp \ - Unicode.cpp + Unicode.cpp \ + file_backup_helper.cpp ifeq ($(TARGET_SIMULATOR),true) LOCAL_SRC_FILES += $(hostSources) diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 2ad3bfe8b898409a80deccd3a38cd6bde4d672f3..3d12dca7a32c9f96516afb168968b7a4071e769a 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -1820,7 +1820,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag } } - if (bestPackage != NULL && bestItem.isBetterThan(thisConfig)) { + if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) { continue; } diff --git a/libs/utils/file_backup_helper.cpp b/libs/utils/file_backup_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..453084ace4524137cda4ff4039a8572da1747034 --- /dev/null +++ b/libs/utils/file_backup_helper.cpp @@ -0,0 +1,685 @@ +#define LOG_TAG "file_backup_helper" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace android; + +#define MAGIC0 0x70616e53 // Snap +#define MAGIC1 0x656c6946 // File + +#define LOGP(x...) LOGD(x) +//#define LOGP(x...) printf(x) + +struct SnapshotHeader { + int magic0; + int fileCount; + int magic1; + int totalSize; +}; + +struct FileState { + int modTime_sec; + int modTime_nsec; + int size; + int crc32; + int nameLen; +}; + +const static int ROUND_UP[4] = { 0, 3, 2, 1 }; + +static inline int +round_up(int n) +{ + return n + ROUND_UP[n % 4]; +} + +static int +read_snapshot_file(int fd, KeyedVector* snapshot) +{ + int bytesRead = 0; + int amt; + SnapshotHeader header; + + amt = read(fd, &header, sizeof(header)); + if (amt != sizeof(header)) { + return errno; + } + bytesRead += amt; + + if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) { + LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1); + return 1; + } + + for (int i=0; iadd(String8(filename, file.nameLen), file); + } + bytesRead += amt; + if (filename != filenameBuf) { + free(filename); + } + if (amt != nameBufSize) { + LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead); + return 1; + } + } + + if (header.totalSize != bytesRead) { + LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n", + header.totalSize, bytesRead); + return 1; + } + + return 0; +} + +static int +write_snapshot_file(int fd, const KeyedVector& snapshot) +{ + int bytesWritten = sizeof(SnapshotHeader); + // preflight size + const int N = snapshot.size(); + for (int i=0; i oldSnapshot; + KeyedVector newSnapshot; + + if (oldSnapshotFD != -1) { + err = read_snapshot_file(oldSnapshotFD, &oldSnapshot); + if (err != 0) { + // On an error, treat this as a full backup. + oldSnapshot.clear(); + } + } + + for (int i=0; i 0) { + // file added + String8 realFilename(base); + realFilename.appendPath(q); + write_update_file(realFilename, q); + m++; + } + else if (cmp < 0) { + // file removed + write_delete_file(p); + n++; + } + else { + // both files exist, check them + String8 realFilename(base); + realFilename.appendPath(q); + const FileState& f = oldSnapshot.valueAt(n); + const FileState& g = newSnapshot.valueAt(m); + + LOGP("%s\n", q.string()); + LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n", + f.modTime_sec, f.modTime_nsec, f.size, f.crc32); + LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n", + g.modTime_sec, g.modTime_nsec, g.size, g.crc32); + if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec + || f.size != g.size || f.crc32 != g.crc32) { + write_update_file(realFilename, p); + } + n++; + m++; + } + } + + // these were deleted + while (n snapshot; + const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap"; + + system("rm -r " SCRATCH_DIR); + mkdir(SCRATCH_DIR, 0777); + + // write + fd = creat(filename, 0666); + if (fd == -1) { + fprintf(stderr, "error creating %s\n", filename); + return 1; + } + + err = write_snapshot_file(fd, snapshot); + + close(fd); + + if (err != 0) { + fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); + return err; + } + + static const unsigned char correct_data[] = { + 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00 + }; + + err = compare_file(filename, correct_data, sizeof(correct_data)); + if (err != 0) { + return err; + } + + // read + fd = open(filename, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "error opening for read %s\n", filename); + return 1; + } + + KeyedVector readSnapshot; + err = read_snapshot_file(fd, &readSnapshot); + if (err != 0) { + fprintf(stderr, "read_snapshot_file failed %d\n", err); + return err; + } + + if (readSnapshot.size() != 0) { + fprintf(stderr, "readSnapshot should be length 0\n"); + return 1; + } + + return 0; +} + +int +backup_helper_test_four() +{ + int err; + int fd; + KeyedVector snapshot; + const char* filename = SCRATCH_DIR "backup_helper_test_four.snap"; + + system("rm -r " SCRATCH_DIR); + mkdir(SCRATCH_DIR, 0777); + + // write + fd = creat(filename, 0666); + if (fd == -1) { + fprintf(stderr, "error opening %s\n", filename); + return 1; + } + + String8 filenames[4]; + FileState states[4]; + + states[0].modTime_sec = 0xfedcba98; + states[0].modTime_nsec = 0xdeadbeef; + states[0].size = 0xababbcbc; + states[0].crc32 = 0x12345678; + states[0].nameLen = -12; + filenames[0] = String8("bytes_of_padding"); + snapshot.add(filenames[0], states[0]); + + states[1].modTime_sec = 0x93400031; + states[1].modTime_nsec = 0xdeadbeef; + states[1].size = 0x88557766; + states[1].crc32 = 0x22334422; + states[1].nameLen = -1; + filenames[1] = String8("bytes_of_padding3"); + snapshot.add(filenames[1], states[1]); + + states[2].modTime_sec = 0x33221144; + states[2].modTime_nsec = 0xdeadbeef; + states[2].size = 0x11223344; + states[2].crc32 = 0x01122334; + states[2].nameLen = 0; + filenames[2] = String8("bytes_of_padding_2"); + snapshot.add(filenames[2], states[2]); + + states[3].modTime_sec = 0x33221144; + states[3].modTime_nsec = 0xdeadbeef; + states[3].size = 0x11223344; + states[3].crc32 = 0x01122334; + states[3].nameLen = 0; + filenames[3] = String8("bytes_of_padding__1"); + snapshot.add(filenames[3], states[3]); + + err = write_snapshot_file(fd, snapshot); + + close(fd); + + if (err != 0) { + fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); + return err; + } + + static const unsigned char correct_data[] = { + // header + 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00, + 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00, + + // bytes_of_padding + 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde, + 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12, + 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, + + // bytes_of_padding3 + 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde, + 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22, + 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab, + + // bytes of padding2 + 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, + 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01, + 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab, + + // bytes of padding3 + 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, + 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01, + 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab + }; + + err = compare_file(filename, correct_data, sizeof(correct_data)); + if (err != 0) { + return err; + } + + // read + fd = open(filename, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "error opening for read %s\n", filename); + return 1; + } + + + KeyedVector readSnapshot; + err = read_snapshot_file(fd, &readSnapshot); + if (err != 0) { + fprintf(stderr, "read_snapshot_file failed %d\n", err); + return err; + } + + if (readSnapshot.size() != 4) { + fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size()); + return 1; + } + + bool matched = true; + for (size_t i=0; i003405.000,3725.3433,12205.7921 003405.000,3725.3433,12205.7921 -003405.000,3725.3433,12205.7921 003405.000,3725.3433,12205.7921 diff --git a/location/data/kml/properties b/location/data/kml/properties deleted file mode 100644 index 42d319f5662c8e5c0f24773d7d5d5305410e3835..0000000000000000000000000000000000000000 --- a/location/data/kml/properties +++ /dev/null @@ -1,11 +0,0 @@ -requiresNetwork false -requiresSatellite false -requiresCell true -hasMonetaryCost false -supportsAltitude true -supportsBearing false -supportsSpeed true -repeat true -accuracy 2 -powerRequirement 2 -trackSpeed 100 diff --git a/location/data/location b/location/data/location deleted file mode 100644 index 1c0c9866186afa1392ef70973b0f101a67dd7ab4..0000000000000000000000000000000000000000 --- a/location/data/location +++ /dev/null @@ -1 +0,0 @@ -gps,1193789209,37.42238666666666666666,-122.096535,0,0,0 diff --git a/location/data/nmea b/location/data/nmea deleted file mode 100644 index 1b6b45b3b62b322fb88fa718eb1354b11c09ee9f..0000000000000000000000000000000000000000 --- a/location/data/nmea +++ /dev/null @@ -1,162 +0,0 @@ -$GPRMC,003350.000,A,3725.3432,N,12205.7921,W,0.06,151.59,061007,,,D*7F -$GPRMC,003355.000,A,3725.3430,N,12205.7920,W,0.18,109.49,061007,,,D*7A -$GPRMC,003400.000,A,3725.3433,N,12205.7921,W,0.02,227.11,061007,,,D*76 -$GPRMC,003405.000,A,3725.3433,N,12205.7921,W,0.17,103.32,061007,,,D*73 -$GPRMC,003410.000,A,3725.3431,N,12205.7921,W,0.22,167.43,061007,,,D*77 -$GPRMC,003415.000,A,3725.3427,N,12205.7921,W,0.23,246.49,061007,,,D*7E -$GPRMC,003420.000,A,3725.3423,N,12205.7917,W,0.16,74.88,061007,,,D*41 -$GPRMC,003425.000,A,3725.3426,N,12205.7919,W,0.05,124.94,061007,,,D*74 -$GPRMC,003430.000,A,3725.3429,N,12205.7919,W,0.15,77.12,061007,,,D*47 -$GPRMC,003435.000,A,3725.3432,N,12205.7921,W,0.07,94.72,061007,,,D*4B -$GPRMC,003440.000,A,3725.3436,N,12205.7921,W,0.13,336.72,061007,,,D*73 -$GPRMC,003445.000,A,3725.3440,N,12205.7953,W,2.72,278.90,061007,,,D*70 -$GPRMC,003450.000,A,3725.3442,N,12205.7977,W,2.02,164.81,061007,,,D*79 -$GPRMC,003455.000,A,3725.3380,N,12205.8008,W,8.28,200.23,061007,,,D*70 -$GPRMC,003500.000,A,3725.3207,N,12205.8057,W,14.04,189.77,061007,,,D*45 -$GPRMC,003505.000,A,3725.3032,N,12205.8094,W,11.67,205.32,061007,,,D*4D -$GPRMC,003510.000,A,3725.2988,N,12205.8295,W,17.09,271.31,061007,,,D*4D -$GPRMC,003515.000,A,3725.3005,N,12205.8672,W,25.02,273.74,061007,,,D*41 -$GPRMC,003520.000,A,3725.3030,N,12205.9159,W,29.84,273.27,061007,,,D*4A -$GPRMC,003525.000,A,3725.3061,N,12205.9683,W,28.20,274.26,061007,,,D*42 -$GPRMC,003530.000,A,3725.3092,N,12206.0150,W,25.25,274.96,061007,,,D*4A -$GPRMC,003535.000,A,3725.3124,N,12206.0503,W,12.55,276.56,061007,,,D*4C -$GPRMC,003540.000,A,3725.3135,N,12206.0637,W,3.99,272.32,061007,,,D*7C -$GPRMC,003545.000,A,3725.3140,N,12206.0701,W,2.80,273.59,061007,,,D*7A -$GPRMC,003550.000,A,3725.3143,N,12206.0734,W,0.84,266.99,061007,,,D*75 -$GPRMC,003555.000,A,3725.3142,N,12206.0731,W,0.13,157.63,061007,,,D*7E -$GPRMC,003600.000,A,3725.3142,N,12206.0729,W,0.16,239.76,061007,,,D*7E -$GPRMC,003605.000,A,3725.3141,N,12206.0726,W,0.15,199.57,061007,,,D*7E -$GPRMC,003610.000,A,3725.3141,N,12206.0724,W,0.07,161.75,061007,,,D*7C -$GPRMC,003615.000,A,3725.3141,N,12206.0721,W,0.14,171.95,061007,,,D*71 -$GPRMC,003620.000,A,3725.3141,N,12206.0718,W,0.12,188.87,061007,,,D*7E -$GPRMC,003625.000,A,3725.3141,N,12206.0716,W,0.14,164.43,061007,,,D*79 -$GPRMC,003630.000,A,3725.3141,N,12206.0714,W,0.10,186.09,061007,,,D*79 -$GPRMC,003635.000,A,3725.3142,N,12206.0716,W,0.09,224.65,061007,,,D*74 -$GPRMC,003640.000,A,3725.3142,N,12206.0716,W,0.09,187.23,061007,,,D*7E -$GPRMC,003645.000,A,3725.3143,N,12206.0716,W,0.14,229.41,061007,,,D*75 -$GPRMC,003650.000,A,3725.3143,N,12206.0716,W,0.14,195.40,061007,,,D*74 -$GPRMC,003655.000,A,3725.3143,N,12206.0716,W,0.51,267.41,061007,,,D*7F -$GPRMC,003700.000,A,3725.3148,N,12206.0813,W,9.83,274.54,061007,,,D*7F -$GPRMC,003705.000,A,3725.3247,N,12206.0930,W,15.25,357.95,061007,,,D*4A -$GPRMC,003710.000,A,3725.3558,N,12206.0907,W,27.03,4.83,061007,,,D*44 -$GPRMC,003715.000,A,3725.3993,N,12206.0862,W,34.76,4.78,061007,,,D*4C -$GPRMC,003720.000,A,3725.4514,N,12206.0802,W,39.38,5.62,061007,,,D*45 -$GPRMC,003725.000,A,3725.5072,N,12206.0756,W,38.59,358.11,061007,,,D*43 -$GPRMC,003730.000,A,3725.5581,N,12206.0877,W,36.13,344.59,061007,,,D*43 -$GPRMC,003735.000,A,3725.6078,N,12206.1038,W,36.78,348.75,061007,,,D*4B -$GPRMC,003740.000,A,3725.6604,N,12206.1021,W,37.66,14.75,061007,,,D*78 -$GPRMC,003745.000,A,3725.7064,N,12206.0817,W,32.70,20.79,061007,,,D*79 -$GPRMC,003750.000,A,3725.7482,N,12206.0613,W,31.70,20.73,061007,,,D*72 -$GPRMC,003755.000,A,3725.7841,N,12206.0458,W,25.05,16.94,061007,,,D*72 -$GPRMC,003800.000,A,3725.8137,N,12206.0368,W,16.01,11.76,061007,,,D*71 -$GPRMC,003805.000,A,3725.8266,N,12206.0341,W,2.45,9.89,061007,,,D*74 -$GPRMC,003810.000,A,3725.8273,N,12206.0340,W,1.42,8.42,061007,,,D*77 -$GPRMC,003815.000,A,3725.8287,N,12206.0340,W,3.02,8.77,061007,,,D*79 -$GPRMC,003820.000,A,3725.8402,N,12206.0321,W,11.90,7.87,061007,,,D*4B -$GPRMC,003825.000,A,3725.8520,N,12206.0422,W,12.90,274.31,061007,,,D*43 -$GPRMC,003830.000,A,3725.8386,N,12206.0610,W,17.45,193.03,061007,,,D*48 -$GPRMC,003835.000,A,3725.8082,N,12206.0693,W,25.06,193.69,061007,,,D*4B -$GPRMC,003840.000,A,3725.7732,N,12206.0836,W,24.74,216.89,061007,,,D*4F -$GPRMC,003845.000,A,3725.7672,N,12206.1208,W,23.64,296.05,061007,,,D*43 -$GPRMC,003850.000,A,3725.7944,N,12206.1530,W,30.80,314.88,061007,,,D*47 -$GPRMC,003855.000,A,3725.8272,N,12206.1893,W,31.57,318.18,061007,,,D*49 -$GPRMC,003900.000,A,3725.8605,N,12206.2264,W,31.13,318.65,061007,,,D*47 -$GPRMC,003905.000,A,3725.8939,N,12206.2625,W,32.39,318.52,061007,,,A*49 -$GPRMC,003910.000,A,3725.9297,N,12206.2994,W,33.37,319.89,061007,,,A*4E -$GPRMC,003915.000,A,3725.9666,N,12206.3378,W,34.92,320.36,061007,,,A*4E -$GPRMC,003920.000,A,3726.0048,N,12206.3777,W,35.91,319.96,061007,,,A*41 -$GPRMC,003925.000,A,3726.0439,N,12206.4186,W,36.78,319.98,061007,,,A*43 -$GPRMC,003930.000,A,3726.0837,N,12206.4602,W,37.26,320.27,061007,,,A*4A -$GPRMC,003935.000,A,3726.1240,N,12206.5024,W,37.88,320.27,061007,,,A*43 -$GPRMC,003940.000,A,3726.1647,N,12206.5449,W,37.95,319.99,061007,,,A*4E -$GPRMC,003945.000,A,3726.2055,N,12206.5874,W,37.24,320.06,061007,,,A*49 -$GPRMC,003950.000,A,3726.2438,N,12206.6274,W,34.50,320.25,061007,,,A*4A -$GPRMC,003955.000,A,3726.2805,N,12206.6661,W,34.75,319.90,061007,,,A*4E -$GPRMC,004000.000,A,3726.3181,N,12206.7054,W,35.63,320.23,061007,,,A*41 -$GPRMC,004005.000,A,3726.3570,N,12206.7462,W,36.84,320.29,061007,,,A*4F -$GPRMC,004010.000,A,3726.3961,N,12206.7872,W,35.85,320.09,061007,,,A*4A -$GPRMC,004015.000,A,3726.4343,N,12206.8276,W,36.84,320.17,061007,,,A*4E -$GPRMC,004020.000,A,3726.4759,N,12206.8712,W,40.53,320.65,061007,,,A*4E -$GPRMC,004025.000,A,3726.5190,N,12206.9164,W,39.54,320.13,061007,,,A*47 -$GPRMC,004030.000,A,3726.5607,N,12206.9605,W,38.84,319.99,061007,,,A*4E -$GPRMC,004035.000,A,3726.6010,N,12207.0030,W,36.82,320.30,061007,,,A*41 -$GPRMC,004040.000,A,3726.6413,N,12207.0416,W,35.63,328.90,061007,,,A*4A -$GPRMC,004045.000,A,3726.6861,N,12207.0652,W,35.49,342.93,061007,,,A*43 -$GPRMC,004050.000,A,3726.7346,N,12207.0842,W,37.15,342.57,061007,,,A*44 -$GPRMC,004055.000,A,3726.7834,N,12207.1033,W,36.68,342.14,061007,,,A*4C -$GPRMC,004100.000,A,3726.8328,N,12207.1225,W,36.73,343.04,061007,,,D*4E -$GPRMC,004105.000,A,3726.8795,N,12207.1405,W,33.44,343.08,061007,,,D*40 -$GPRMC,004110.000,A,3726.9211,N,12207.1570,W,28.00,343.17,061007,,,D*4B -$GPRMC,004115.000,A,3726.9507,N,12207.1678,W,18.59,345.92,061007,,,D*41 -$GPRMC,004120.000,A,3726.9639,N,12207.1722,W,3.24,343.37,061007,,,D*7E -$GPRMC,004125.000,A,3726.9641,N,12207.1725,W,0.21,154.73,061007,,,D*71 -$GPRMC,004130.000,A,3726.9634,N,12207.1722,W,0.16,105.89,061007,,,D*75 -$GPRMC,004135.000,A,3726.9630,N,12207.1720,W,0.04,133.97,061007,,,D*7F -$GPRMC,004140.000,A,3726.9627,N,12207.1718,W,0.16,107.47,061007,,,D*79 -$GPRMC,004145.000,A,3726.9625,N,12207.1716,W,0.14,148.73,061007,,,D*7E -$GPRMC,004150.000,A,3726.9621,N,12207.1715,W,0.09,142.18,061007,,,D*76 -$GPRMC,004155.000,A,3726.9620,N,12207.1714,W,0.10,95.75,061007,,,D*4B -$GPRMC,004200.000,A,3726.9618,N,12207.1714,W,0.07,135.28,061007,,,D*76 -$GPRMC,004205.000,A,3726.9617,N,12207.1713,W,0.14,86.20,061007,,,D*48 -$GPRMC,004210.000,A,3726.9616,N,12207.1713,W,0.05,130.34,061007,,,D*74 -$GPRMC,004215.000,A,3726.9614,N,12207.1714,W,0.08,120.53,061007,,,D*79 -$GPRMC,004220.000,A,3726.9612,N,12207.1714,W,0.09,147.27,061007,,,D*7A -$GPRMC,004225.000,A,3726.9612,N,12207.1715,W,0.12,118.20,061007,,,D*79 -$GPRMC,004230.000,A,3726.9612,N,12207.1714,W,0.12,90.61,061007,,,D*48 -$GPRMC,004235.000,A,3726.9612,N,12207.1715,W,0.10,156.15,061007,,,D*76 -$GPRMC,004240.000,A,3726.9612,N,12207.1715,W,0.13,104.74,061007,,,D*77 -$GPRMC,004245.000,A,3726.9617,N,12207.1716,W,2.21,343.16,061007,,,D*72 -$GPRMC,004250.000,A,3726.9756,N,12207.1772,W,15.37,342.52,061007,,,D*40 -$GPRMC,004255.000,A,3726.9950,N,12207.1942,W,16.40,298.08,061007,,,D*4A -$GPRMC,004300.000,A,3726.9896,N,12207.2215,W,18.97,241.60,061007,,,D*44 -$GPRMC,004305.000,A,3726.9801,N,12207.2558,W,22.01,268.09,061007,,,D*43 -$GPRMC,004310.000,A,3726.9908,N,12207.2943,W,24.76,304.28,061007,,,D*47 -$GPRMC,004315.000,A,3727.0088,N,12207.3347,W,27.35,295.83,061007,,,D*48 -$GPRMC,004320.000,A,3727.0117,N,12207.3855,W,28.97,271.02,061007,,,D*45 -$GPRMC,004325.000,A,3727.0211,N,12207.4306,W,22.94,303.62,061007,,,D*44 -$GPRMC,004330.000,A,3727.0358,N,12207.4491,W,8.59,313.76,061007,,,D*78 -$GPRMC,004335.000,A,3727.0409,N,12207.4550,W,2.33,313.55,061007,,,D*75 -$GPRMC,004340.000,A,3727.0433,N,12207.4578,W,5.75,314.25,061007,,,D*71 -$GPRMC,004345.000,A,3727.0533,N,12207.4704,W,12.55,314.18,061007,,,D*46 -$GPRMC,004350.000,A,3727.0676,N,12207.4892,W,16.68,312.98,061007,,,D*44 -$GPRMC,004355.000,A,3727.0835,N,12207.5103,W,15.11,313.21,061007,,,D*46 -$GPRMC,004400.000,A,3727.0969,N,12207.5285,W,10.26,312.85,061007,,,D*4A -$GPRMC,004405.000,A,3727.1006,N,12207.5334,W,0.33,319.16,061007,,,D*71 -$GPRMC,004410.000,A,3727.1007,N,12207.5333,W,0.19,144.98,061007,,,D*77 -$GPRMC,004415.000,A,3727.1005,N,12207.5330,W,0.05,106.63,061007,,,D*7C -$GPRMC,004420.000,A,3727.1006,N,12207.5327,W,0.05,92.53,061007,,,D*40 -$GPRMC,004425.000,A,3727.1005,N,12207.5323,W,0.17,148.57,061007,,,D*73 -$GPRMC,004430.000,A,3727.1037,N,12207.5355,W,8.70,314.52,061007,,,D*70 -$GPRMC,004435.000,A,3727.1168,N,12207.5516,W,16.83,312.51,061007,,,D*49 -$GPRMC,004440.000,A,3727.1344,N,12207.5787,W,23.06,309.71,061007,,,D*4E -$GPRMC,004445.000,A,3727.1572,N,12207.6136,W,27.67,308.29,061007,,,D*48 -$GPRMC,004450.000,A,3727.1821,N,12207.6558,W,31.56,306.08,061007,,,D*43 -$GPRMC,004455.000,A,3727.2083,N,12207.7008,W,30.81,306.19,061007,,,D*4F -$GPRMC,004500.000,A,3727.2324,N,12207.7424,W,27.68,306.75,061007,,,D*41 -$GPRMC,004505.000,A,3727.2519,N,12207.7754,W,16.50,305.19,061007,,,D*48 -$GPRMC,004510.000,A,3727.2570,N,12207.7849,W,0.13,151.16,061007,,,D*7C -$GPRMC,004515.000,A,3727.2619,N,12207.7927,W,14.27,311.27,061007,,,D*4A -$GPRMC,004520.000,A,3727.2786,N,12207.8214,W,23.53,303.48,061007,,,D*42 -$GPRMC,004525.000,A,3727.2980,N,12207.8564,W,25.03,306.82,061007,,,D*4F -$GPRMC,004530.000,A,3727.3199,N,12207.8936,W,27.48,306.29,061007,,,D*4D -$GPRMC,004535.000,A,3727.3433,N,12207.9339,W,28.66,306.28,061007,,,D*4B -$GPRMC,004540.000,A,3727.3666,N,12207.9740,W,28.04,306.12,061007,,,D*4C -$GPRMC,004545.000,A,3727.3886,N,12208.0118,W,25.22,306.50,061007,,,D*4B -$GPRMC,004550.000,A,3727.4091,N,12208.0461,W,23.34,306.68,061007,,,D*47 -$GPRMC,004555.000,A,3727.4291,N,12208.0747,W,19.76,317.26,061007,,,D*42 -$GPRMC,004600.000,A,3727.4497,N,12208.1015,W,24.00,309.28,061007,,,D*4E -$GPRMC,004605.000,A,3727.4711,N,12208.1376,W,26.83,305.61,061007,,,D*48 -$GPRMC,004610.000,A,3727.4937,N,12208.1760,W,26.40,305.68,061007,,,D*43 -$GPRMC,004615.000,A,3727.5142,N,12208.2112,W,23.46,306.19,061007,,,D*4B -$GPRMC,004620.000,A,3727.5326,N,12208.2431,W,21.96,304.30,061007,,,D*4F -$GPRMC,004625.000,A,3727.5515,N,12208.2693,W,20.21,323.71,061007,,,D*4B -$GPRMC,004630.000,A,3727.5788,N,12208.2812,W,21.00,352.36,061007,,,D*49 -$GPRMC,004635.000,A,3727.6048,N,12208.2846,W,14.79,351.69,061007,,,D*44 -$GPRMC,004640.000,A,3727.6217,N,12208.2861,W,6.38,359.46,061007,,,D*78 -$GPRMC,004645.000,A,3727.6322,N,12208.2880,W,10.02,331.10,061007,,,D*46 -$GPRMC,004650.000,A,3727.6394,N,12208.3010,W,6.76,277.11,061007,,,D*79 -$GPRMC,004655.000,A,3727.6382,N,12208.3058,W,1.58,256.67,061007,,,D*7E -$GPRMC,004700.000,A,3727.6253,N,12208.3024,W,6.34,164.31,061007,,,A*70 -$GPRMC,004715.000,A,3727.5854,N,12208.3345,W,5.00,267.98,061007,,,A*79 -$GPRMC,004720.000,A,3727.5993,N,12208.3323,W,6.50,26.91,061007,,,A*4D -$GPRMC,004725.000,A,3727.6123,N,12208.3159,W,13.14,44.68,061007,,,A*71 diff --git a/location/data/properties b/location/data/properties deleted file mode 100644 index b6878affb10b6014f5a6c8478a4f0a438cef7e54..0000000000000000000000000000000000000000 --- a/location/data/properties +++ /dev/null @@ -1,10 +0,0 @@ -requiresNetwork false -requiresSatellite false -requiresCell false -hasMonetaryCost false -supportsAltitude true -supportsBearing true -supportsSpeed true -repeat true -accuracy 1 -powerRequirement 1 diff --git a/location/data/test/class b/location/data/test/class deleted file mode 100644 index 495b1720a755a2ebf594c188827936b1088d5f82..0000000000000000000000000000000000000000 --- a/location/data/test/class +++ /dev/null @@ -1 +0,0 @@ -android.test.TestLocationProvider diff --git a/location/data/track/properties b/location/data/track/properties deleted file mode 100644 index 1f1ed5e4b8b1da1e30d1faad9fe01844955bd67f..0000000000000000000000000000000000000000 --- a/location/data/track/properties +++ /dev/null @@ -1,10 +0,0 @@ -requiresNetwork true -requiresSatellite false -requiresCell false -hasMonetaryCost false -supportsAltitude true -supportsBearing false -supportsSpeed false -repeat true -accuracy 1 -powerRequirement 3 diff --git a/location/data/track/track b/location/data/track/track deleted file mode 100644 index a69ba2a18ef528a03afe62b57bf514a36f87f422..0000000000000000000000000000000000000000 --- a/location/data/track/track +++ /dev/null @@ -1 +0,0 @@ -00 003405.000 3725.3433 12205.7921 101.2 65.3 diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java index 709ad23fd7875d159a7687e222e0b3a472072734..53e46b7d200108391e31f9b0e0734f4bfc24a13d 100644 --- a/location/java/android/location/Geocoder.java +++ b/location/java/android/location/Geocoder.java @@ -36,7 +36,11 @@ import java.util.List; * coordinate into a (partial) address. The amount of detail in a * reverse geocoded location description may vary, for example one * might contain the full street address of the closest building, while - * another might contain only a city name and postal code. + * another might contain only a city name and postal code. + * + * The Geocoder class requires a backend service that is not included in + * the core android framework. The Geocoder query methods will return an + * empty list if there no backend service in the platform. */ public final class Geocoder { private static final String TAG = "Geocoder"; @@ -94,8 +98,8 @@ public final class Geocoder { * @param longitude the longitude a point for the search * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended * - * @return a list of Address objects or null if no matches were - * found. + * @return a list of Address objects. Returns null or empty list if no matches were + * found or there is no backend service available. * * @throws IllegalArgumentException if latitude is * less than -90 or greater than 90 @@ -143,7 +147,8 @@ public final class Geocoder { * @param locationName a user-supplied description of a location * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended * - * @return a list of Address objects or null if no matches were found. + * @return a list of Address objects. Returns null or empty list if no matches were + * found or there is no backend service available. * * @throws IllegalArgumentException if locationName is null * @throws IOException if the network is unavailable or any other @@ -192,7 +197,8 @@ public final class Geocoder { * @param upperRightLatitude the latitude of the upper right corner of the bounding box * @param upperRightLongitude the longitude of the upper right corner of the bounding box * - * @return a list of Address objects or null if no matches were found. + * @return a list of Address objects. Returns null or empty list if no matches were + * found or there is no backend service available. * * @throws IllegalArgumentException if locationName is null * @throws IllegalArgumentException if any latitude is diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java index a40b1fb2acbd018a4fedbf98ae43e50000124807..2cda7faafa547cd7d649bd1d5b2b7cdda4097fdb 100644 --- a/location/java/android/location/GpsStatus.java +++ b/location/java/android/location/GpsStatus.java @@ -25,7 +25,7 @@ import java.util.NoSuchElementException; * This class is used in conjunction with the {@link Listener} interface. */ public final class GpsStatus { - private static final int NUM_SATELLITES = 32; + private static final int NUM_SATELLITES = 255; /* These package private values are modified by the LocationManager class */ private int mTimeToFirstFix; diff --git a/location/java/android/location/IGeocodeProvider.aidl b/location/java/android/location/IGeocodeProvider.aidl new file mode 100644 index 0000000000000000000000000000000000000000..e79e8d2db623a978f1f7c7ea98c46e0dffdd6543 --- /dev/null +++ b/location/java/android/location/IGeocodeProvider.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.location.Address; + +/** + * An interface for location providers implementing the Geocoder services. + * + * {@hide} + */ +interface IGeocodeProvider { + + String getFromLocation(double latitude, double longitude, int maxResults, + String language, String country, String variant, String appName, out List
          addrs); + + String getFromLocationName(String locationName, + double lowerLeftLatitude, double lowerLeftLongitude, + double upperRightLatitude, double upperRightLongitude, int maxResults, + String language, String country, String variant, String appName, out List
          addrs); +} diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/location/java/android/location/IGpsStatusProvider.aidl new file mode 100644 index 0000000000000000000000000000000000000000..cf277c8c5d01d2517c5225a218f39eea5af9adb2 --- /dev/null +++ b/location/java/android/location/IGpsStatusProvider.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.location.IGpsStatusListener; + +/** + * An interface for location providers that provide GPS status information. + * + * {@hide} + */ +interface IGpsStatusProvider { + void addGpsStatusListener(IGpsStatusListener listener); + void removeGpsStatusListener(IGpsStatusListener listener); +} diff --git a/location/java/com/android/internal/location/INetworkLocationManager.java b/location/java/android/location/ILocationCollector.aidl similarity index 51% rename from location/java/com/android/internal/location/INetworkLocationManager.java rename to location/java/android/location/ILocationCollector.aidl index d85ff0a5c79a92f7c14f18b1fb0469fc1396c02c..b2e17969814c508e4ac6f5f48320d0bf8205c4fc 100644 --- a/location/java/com/android/internal/location/INetworkLocationManager.java +++ b/location/java/android/location/ILocationCollector.aidl @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,24 +14,23 @@ * limitations under the License. */ -package com.android.internal.location; +package android.location; -import android.content.Context; +import android.location.Location; /** - * Used to register network location and collection services - * with the Location Manager Service. + * Listens for GPS and cell/wifi changes and anonymously uploads to server + * for improving quality of service of NetworkLocationProvider. + * This service is only enabled when the user has enabled the + * network location provider. * * {@hide} */ -public interface INetworkLocationManager { - - /* callback to allow installation to occur in Location Manager's thread */ - public interface InstallCallback { - void installNetworkLocationProvider(INetworkLocationManager manager); - } - - void setInstallCallback(InstallCallback callback); - void setNetworkLocationProvider(INetworkLocationProvider provider); - void setLocationCollector(ILocationCollector collector); -} \ No newline at end of file +oneway interface ILocationCollector { + /** + * Updates GPS location if collection is enabled + * + * @param location location object + */ + void updateLocation(in Location location); +} diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 69c404a3d70c4a6e4234f5817cd0b0e67372bd8d..2c214c9ef3b64fbc864f23d832773153d13d0d90 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -18,8 +18,11 @@ package android.location; import android.app.PendingIntent; import android.location.Address; +import android.location.IGeocodeProvider; import android.location.IGpsStatusListener; +import android.location.ILocationCollector; import android.location.ILocationListener; +import android.location.ILocationProvider; import android.location.Location; import android.os.Bundle; @@ -33,8 +36,6 @@ interface ILocationManager List getAllProviders(); List getProviders(boolean enabledOnly); - void updateProviders(); - void requestLocationUpdates(String provider, long minTime, float minDistance, in ILocationListener listener); void requestLocationUpdatesPI(String provider, long minTime, float minDistance, @@ -44,7 +45,10 @@ interface ILocationManager boolean addGpsStatusListener(IGpsStatusListener listener); void removeGpsStatusListener(IGpsStatusListener listener); - + + // for reporting callback completion + void locationCallbackFinished(ILocationListener listener); + boolean sendExtraCommand(String provider, String command, inout Bundle extras); void addProximityAlert(double latitude, double longitude, float distance, @@ -56,6 +60,9 @@ interface ILocationManager Location getLastKnownLocation(String provider); + /* used by location providers to tell the location manager when it has a new location */ + void reportLocation(in Location location); + String getFromLocation(double latitude, double longitude, int maxResults, String language, String country, String variant, String appName, out List
          addrs); String getFromLocationName(String locationName, @@ -73,4 +80,9 @@ interface ILocationManager void clearTestProviderEnabled(String provider); void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime); void clearTestProviderStatus(String provider); + + /* for installing external Location Providers */ + void installLocationProvider(String name, ILocationProvider provider); + void installLocationCollector(ILocationCollector collector); + void installGeocodeProvider(IGeocodeProvider provider); } diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl new file mode 100644 index 0000000000000000000000000000000000000000..6c23f838a955bb29672561c51f9e67b2e497e11b --- /dev/null +++ b/location/java/android/location/ILocationProvider.aidl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.os.Bundle; + +/** + * Binder interface for location providers. + * + * {@hide} + */ +interface ILocationProvider { + boolean requiresNetwork(); + boolean requiresSatellite(); + boolean requiresCell(); + boolean hasMonetaryCost(); + boolean supportsAltitude(); + boolean supportsSpeed(); + boolean supportsBearing(); + int getPowerRequirement(); + int getAccuracy(); + void enable(); + void disable(); + boolean isEnabled(); + int getStatus(out Bundle extras); + long getStatusUpdateTime(); + void enableLocationTracking(boolean enable); + void setMinTime(long minTime); + void updateNetworkState(int state); + boolean sendExtraCommand(String command, inout Bundle extras); + void addListener(int uid); + void removeListener(int uid); +} diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 022ee25c44e1c584a88e83271e24e95923d17a94..872838c732bd0c174d189de8e3faa7160db4221a 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -26,6 +26,8 @@ import android.os.Message; import android.util.Config; import android.util.Log; +import com.android.internal.location.DummyLocationProvider; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -101,9 +103,6 @@ public class LocationManager { */ public static final String KEY_LOCATION_CHANGED = "location"; - /** @hide -- does this belong here? */ - public static final String PROVIDER_DIR = "/data/location"; - /** @hide */ public static final String SYSTEM_DIR = "/data/system/location"; @@ -194,6 +193,11 @@ public class LocationManager { mListener.onProviderDisabled((String) msg.obj); break; } + try { + mService.locationCallbackFinished(this); + } catch (RemoteException e) { + Log.e(TAG, "locationCallbackFinished: RemoteException", e); + } } } /** @@ -312,20 +316,6 @@ public class LocationManager { return goodProviders; } - /** - * Propagates the enabled/disabled state of the providers from the system - * settings to the providers themselves. - * - * {@hide} - */ - public void updateProviders() { - try { - mService.updateProviders(); - } catch (RemoteException ex) { - Log.e(TAG, "updateProviders: RemoteException", ex); - } - } - /** * Returns the next looser power requirement, in the sequence: * @@ -1265,4 +1255,85 @@ public class LocationManager { return false; } } + + /** + * Installs a location provider. + * + * @param name of the location provider + * @param provider Binder interface for the location provider + * + * @return true if the command succeeds. + * + * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. + * + * {@hide} + */ + public boolean installLocationProvider(String name, ILocationProvider provider) { + try { + mService.installLocationProvider(name, provider); + return true; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in installLocationProvider: ", e); + return false; + } + } + + /** + * Installs a location collector. + * + * @param provider Binder interface for the location collector + * + * @return true if the command succeeds. + * + * Requires the android.permission.INSTALL_LOCATION_COLLECTOR permission. + * + * {@hide} + */ + public boolean installLocationCollector(ILocationCollector collector) { + try { + mService.installLocationCollector(collector); + return true; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setLocationCollector: ", e); + return false; + } + } + + /** + * Installs a geocoder server. + * + * @param provider Binder interface for the geocoder provider + * + * @return true if the command succeeds. + * + * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. + * + * {@hide} + */ + public boolean installGeocodeProvider(IGeocodeProvider provider) { + try { + mService.installGeocodeProvider(provider); + return true; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setGeocodeProvider: ", e); + return false; + } + } + + /** + * Used by location providers to report new locations. + * + * @param location new Location to report + * + * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. + * + * {@hide} + */ + public void reportLocation(Location location) { + try { + mService.reportLocation(location); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in reportLocation: ", e); + } + } } diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java index b1670d505dee76056dbc1765015adac2661a1e40..3faba58567eb759b8f225fcd1b3f45498ab05651 100644 --- a/location/java/android/location/LocationProvider.java +++ b/location/java/android/location/LocationProvider.java @@ -47,8 +47,10 @@ public abstract class LocationProvider { * consist only of the characters [a-zA-Z0-9]. * * @throws IllegalArgumentException if name contains an illegal character + * + * {@hide} */ - LocationProvider(String name) { + public LocationProvider(String name) { if (name.matches(BAD_CHARS_REGEX)) { throw new IllegalArgumentException("name " + name + " contains an illegal character"); diff --git a/location/java/android/location/LocationProviderImpl.java b/location/java/android/location/LocationProviderImpl.java deleted file mode 100644 index 0962992c61f05e62acd2e8f1934c8df5e627f83f..0000000000000000000000000000000000000000 --- a/location/java/android/location/LocationProviderImpl.java +++ /dev/null @@ -1,261 +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 android.location; - -import com.android.internal.location.CellState; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import android.os.Bundle; -import android.util.Config; -import android.util.Log; - -/** - * An abstract superclass for location provider implementations. - * Location provider implementations are typically instantiated by the - * location manager service in the system process, and location - * information is made available to implementations via the manager. - * - * {@hide} - */ -public abstract class LocationProviderImpl extends LocationProvider { - private static final String TAG = "LocationProviderImpl"; - - private static ArrayList sProviders = - new ArrayList(); - private static HashMap sProvidersByName - = new HashMap(); - - private boolean mLocationTracking = false; - private long mMinTime = 0; - - protected LocationProviderImpl(String name) { - super(name); - } - - public static void addProvider(LocationProviderImpl provider) { - sProviders.add(provider); - sProvidersByName.put(provider.getName(), provider); - } - - public static void removeProvider(LocationProviderImpl provider) { - sProviders.remove(provider); - sProvidersByName.remove(provider.getName()); - } - - public static List getProviders() { - return new ArrayList(sProviders); - } - - public static LocationProviderImpl getProvider(String name) { - return sProvidersByName.get(name); - } - - public static LocationProviderImpl loadFromClass(File classFile) { - if (!classFile.exists()) { - return null; - } - if (Config.LOGD) { - Log.d(TAG, "Loading class specifier file " + classFile.getPath()); - } - String className = null; - try { - BufferedReader br = - new BufferedReader(new FileReader(classFile), 8192); - className = br.readLine(); - br.close(); - Class providerClass = Class.forName(className); - if (Config.LOGD) { - Log.d(TAG, "Loading provider class " + providerClass.getName()); - } - LocationProviderImpl provider = - (LocationProviderImpl) providerClass.newInstance(); - if (Config.LOGD) { - Log.d(TAG, "Got provider instance " + provider); - } - - return provider; - } catch (IOException ioe) { - Log.e(TAG, "IOException loading config file " + - classFile.getPath(), ioe); - } catch (IllegalAccessException iae) { - Log.e(TAG, "IllegalAccessException loading class " + - className, iae); - } catch (InstantiationException ie) { - Log.e(TAG, "InstantiationException loading class " + - className, ie); - } catch (ClassNotFoundException cnfe) { - Log.e(TAG, "ClassNotFoundException loading class " + - className, cnfe); - } catch (ClassCastException cce) { - Log.e(TAG, "ClassCastException loading class " + - className, cce); - } - return null; - } - - /** - * Enables this provider. When enabled, calls to {@link #getStatus()} - * and {@link #getLocation} must be handled. Hardware may be started up - * when the provider is enabled. - */ - public abstract void enable(); - - /** - * Disables this provider. When disabled, calls to {@link #getStatus()} - * and {@link #getLocation} need not be handled. Hardware may be shut - * down while the provider is disabled. - */ - public abstract void disable(); - - /** - * Returns true if this provider is enabled, false otherwise; - */ - public abstract boolean isEnabled(); - - /** - * Returns a information on the status of this provider. - * {@link #OUT_OF_SERVICE} is returned if the provider is - * out of service, and this is not expected to change in the near - * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if - * the provider is temporarily unavailable but is expected to be - * available shortly; and {@link #AVAILABLE} is returned - * if the provider is currently available. - */ - public int getStatus() { - return getStatus(null); - } - - /** - * Returns a information on the status of this provider. - * {@link #OUT_OF_SERVICE} is returned if the provider is - * out of service, and this is not expected to change in the near - * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if - * the provider is temporarily unavailable but is expected to be - * available shortly; and {@link #AVAILABLE} is returned - * if the provider is currently available. - * - *

          If extras is non-null, additional status information may be - * added to it in the form of provider-specific key/value pairs. - */ - public abstract int getStatus(Bundle extras); - - /** - * Returns the time at which the status was last updated. It is the - * responsibility of the provider to appropriately set this value - * using {@link android.os.SystemClock.elapsedRealtime()} each time - * there is a status update that it wishes to broadcast to all its - * listeners. The provider should be careful not to broadcast - * the same status again. - * - * @return time of last status update in millis since last reboot - */ - public long getStatusUpdateTime() { - return 0; - } - - /** - * Sets a Location object with the information gathered - * during the most recent fix. - * - * @param l location object to set - * @return true if a location fix is available - */ - public abstract boolean getLocation(Location l); - - /** - * Notifies the location provider that clients are listening for locations. - * Called with enable set to true when the first client is added and - * called with enable set to false when the last client is removed. - * This allows the provider to prepare for receiving locations, - * and to shut down when no clients are remaining. - * - * @param enable true if location tracking should be enabled. - */ - public void enableLocationTracking(boolean enable) { - mLocationTracking = enable; - } - - /** - * Returns true if the provider has any listeners - * - * @return true if provider is being tracked - */ - public boolean isLocationTracking() { - return mLocationTracking; - } - - /** - * Notifies the location provider of the smallest minimum time between updates amongst - * all clients that are listening for locations. This allows the provider to reduce - * the frequency of updates to match the requested frequency. - * - * @param minTime the smallest minTime value over all listeners for this provider. - */ - public void setMinTime(long minTime) { - mMinTime = minTime; - } - - /** - * Gets the smallest minimum time between updates amongst all the clients listening - * for locations. By default this value is 0 (as frqeuently as possible) - * - * @return the smallest minTime value over all listeners for this provider - */ - public long getMinTime() { - return mMinTime; - } - - /** - * Updates the network state for the given provider. This function must - * be overwritten if {@link #requiresNetwork} returns true. The state is - * {@link #TEMPORARILY_UNAVAILABLE} (disconnected), OR {@link #AVAILABLE} - * (connected or connecting). - * - * @param state data state - */ - public void updateNetworkState(int state) { - } - - /** - * Updates the cell state for the given provider. This function must be - * overwritten if {@link #requiresCell} returns true. - * - * @param state cell state - */ - public void updateCellState(CellState state) { - } - - /** - * Implements addditional location provider specific additional commands. - * - * @param command name of the command to send to the provider. - * @param extras optional arguments for the command (or null). - * The provider may optionally fill the extras Bundle with results from the command. - * - * @return true if the command succeeds. - */ - public boolean sendExtraCommand(String command, Bundle extras) { - return false; - } -} diff --git a/location/java/com/android/internal/location/CellState.java b/location/java/com/android/internal/location/CellState.java deleted file mode 100644 index eb6535e8c4288d86f860d8db18b46af6cf65a991..0000000000000000000000000000000000000000 --- a/location/java/com/android/internal/location/CellState.java +++ /dev/null @@ -1,292 +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.location; - -import android.telephony.CellLocation; -import android.telephony.TelephonyManager; -import android.telephony.NeighboringCellInfo; -import android.telephony.gsm.GsmCellLocation; -import android.util.Log; - -import com.android.internal.telephony.TelephonyProperties; - -import java.util.List; -import java.util.ArrayList; - -import android.os.SystemProperties; - -/** - * Stores the cell tower state - * - * {@hide} - */ -public class CellState { - - public static String TAG = "CellState"; - - public static int RADIO_TYPE_GPRS = 1; - public static int RADIO_TYPE_CDMA = 2; - public static int RADIO_TYPE_WCDMA = 3; - - private int mCid = -1; - private int mLac = -1; - private int mMcc = -1; - private int mMnc = -1; - private int mHomeMcc = -1; - private int mHomeMnc = -1; - private String mCarrier = null; - private int mRadioType = -1; - private long mTime = 0; - private int mSignalStrength = -1; - - private List mNeighbors; - - public CellState() { - // constructor for invalid cell location - } - - public CellState(TelephonyManager telephonyManager, CellLocation location, int signalStrength) { - GsmCellLocation loc = (GsmCellLocation)location; - mLac = loc.getLac(); // example: 6032 - mCid = loc.getCid(); // example: 31792 - mTime = System.currentTimeMillis(); - - // Get radio type - int radioType = telephonyManager.getNetworkType(); - if (radioType == TelephonyManager.NETWORK_TYPE_GPRS || - radioType == TelephonyManager.NETWORK_TYPE_EDGE) { - mRadioType = RADIO_TYPE_GPRS; - } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) { - mRadioType = RADIO_TYPE_WCDMA; - } - - // Get neighboring cells - mNeighbors = new ArrayList(); - List neighboringCells = telephonyManager.getNeighboringCellInfo(); - if (neighboringCells != null) { - for (NeighboringCellInfo n : neighboringCells) { - if (n.getCid() == NeighboringCellInfo.UNKNOWN_CID) { - continue; - } - - if (mRadioType == RADIO_TYPE_WCDMA) { - mNeighbors.add(new NeighborCell(-1, -1, n.getCid(), n.getRssi())); - } else if (mRadioType == RADIO_TYPE_GPRS) { - try { - String hexCidLac = Integer.toHexString(n.getCid()); - int l = hexCidLac.length(); - if (l > 8) { - Log.w(TAG, "Unable to parse 2G Cell \"" + hexCidLac + "\""); - continue; - } - if (l < 8) { - for (int i = 0; i < (8-l); i++) { - hexCidLac = "0" + hexCidLac; - } - } - int lac = Integer.valueOf(hexCidLac.substring(0, 4), 16); - int cid = Integer.valueOf(hexCidLac.substring(4), 16); - mNeighbors.add(new NeighborCell(cid, lac, -1, n.getRssi())); - - } catch (Exception e) { - Log.e(TAG, "Error parsing 2G Cell \"" + n.getCid() + "\"", e); - } - } - } - } - - // Get MCC/MNC - String operator = telephonyManager.getNetworkOperator(); - if (operator != null && !operator.equals("")) { - // Use a try/catch block to detect index out of bounds or number format exceptions. - // If an error occurs, both mMcc and mMnc will be equal to -1. - try { - String mcc = operator.substring(0, 3); - String mnc = operator.substring(3); - int mccTmp = Integer.parseInt(mcc); - int mncTmp = Integer.parseInt(mnc); - - // Parsing succeeded, update the instance variables together - mMcc = mccTmp; - mMnc = mncTmp; - } catch (Exception e) { - Log.e(TAG, "Error parsing MCC/MNC from operator \"" + operator + "\"", e); - } - } - - // Get Home MCC/MNC - String homeOperator = telephonyManager.getSimOperator(); - if (homeOperator != null && !homeOperator.equals("")) { - // Use a try/catch block to detect index out of bounds or number format exceptions. - // If an error occurs, both mHomeMcc and mHomeMnc will be equal to -1. - try { - String mcc = homeOperator.substring(0, 3); - String mnc = homeOperator.substring(3); - int mccTmp = Integer.parseInt(mcc); - int mncTmp = Integer.parseInt(mnc); - - // Parsing succeeded, update the instance variables together - mHomeMcc = mccTmp; - mHomeMnc = mncTmp; - } catch (Exception e) { - Log.e(TAG, "Error parsing MCC/MNC from home operator \"" + homeOperator + "\"", e); - } - } - - // Get Carrier - String carrier = telephonyManager.getNetworkOperatorName(); - if (carrier != null && !carrier.equals("")) { - mCarrier = carrier; - } - - // Initial signal strength - mSignalStrength = signalStrength; - - if (Log.isLoggable(TAG, Log.VERBOSE)) { - String neighbors = "["; - for (NeighborCell n : mNeighbors) { - neighbors += n.toString() + ","; - } - neighbors += "]"; - Log.d(TAG, "CellState(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + - mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + - mSignalStrength + "," + neighbors); - } - } - - public void updateRadioType(int radioType) { - mRadioType = radioType; - - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.d(TAG, "updateRadioType(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + - mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + - mSignalStrength); - } - } - - public void updateSignalStrength(int signalStrength) { - mSignalStrength = signalStrength; - - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.d(TAG, "updateSignal(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + - mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + - mSignalStrength); - } - } - - public int getCid() { - return mCid; - } - - public int getLac() { - return mLac; - } - - public int getMcc() { - return mMcc; - } - - public int getMnc() { - return mMnc; - } - - public int getHomeMcc() { - return mHomeMcc; - } - - public void setHomeMcc(int homeMcc) { - this.mHomeMcc = homeMcc; - } - - public int getHomeMnc() { - return mHomeMnc; - } - - public void setHomeMnc(int homeMnc) { - this.mHomeMnc = homeMnc; - } - - public String getCarrier() { - return mCarrier; - } - - public void setCarrier(String carrier) { - this.mCarrier = carrier; - } - - public int getRadioType() { - return mRadioType; - } - - public long getTime() { - return mTime; - } - - public int getSignalStrength() { - return mSignalStrength; - } - - public List getNeighbors() { - return mNeighbors; - } - - public boolean equals(CellState other) { - return (mCid == other.mCid && mLac == other.mLac); - } - - public boolean isValid() { - return (mCid != -1 && mLac != -1); - } - - public static class NeighborCell { - private int mCid = -1; - private int mLac = -1; - private int mPsc = -1; - private int mRssi = -1; - - NeighborCell(int cid, int lac, int psc, int rssi) { - mCid = cid; - mLac = lac; - mPsc = psc; - mRssi = rssi; - } - - public int getCid() { - return mCid; - } - - public int getLac() { - return mLac; - } - - public int getPsc() { - return mPsc; - } - - public int getRssi() { - return mRssi; - } - - public String toString() { - if (mPsc != -1) { - return String.valueOf(mPsc) + "@" + mRssi; - } else { - return mCid + ":" + mLac + "@" + mRssi; - } - } - } -} diff --git a/location/java/android/location/DummyLocationProvider.java b/location/java/com/android/internal/location/DummyLocationProvider.java similarity index 96% rename from location/java/android/location/DummyLocationProvider.java rename to location/java/com/android/internal/location/DummyLocationProvider.java index e1cd4e940c58dd5be8fee911c5b6b8048d7059ef..ff5e27b086f7042a20f2d3111297ba284e392bcf 100644 --- a/location/java/android/location/DummyLocationProvider.java +++ b/location/java/com/android/internal/location/DummyLocationProvider.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package android.location; +package com.android.internal.location; + +import android.location.LocationProvider; /** * A stub implementation of LocationProvider used by LocationManager. @@ -24,7 +26,7 @@ package android.location; * * {@hide} */ -class DummyLocationProvider extends LocationProvider { +public class DummyLocationProvider extends LocationProvider { private static final String TAG = "DummyLocationProvider"; @@ -39,7 +41,7 @@ class DummyLocationProvider extends LocationProvider { int mPowerRequirement; int mAccuracy; - /* package */ DummyLocationProvider(String name) { + public DummyLocationProvider(String name) { super(name); } diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java index 887574a66bad13cdfdd11d9325b74789f24ac912..565859cca62282ac778a82b759f5cc60e95d074a 100644 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/location/java/com/android/internal/location/GpsLocationProvider.java @@ -16,24 +16,33 @@ package com.android.internal.location; +import android.app.AlarmManager; +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.IGpsStatusListener; +import android.location.IGpsStatusProvider; +import android.location.ILocationManager; +import android.location.ILocationProvider; import android.location.Location; import android.location.LocationManager; import android.location.LocationProvider; -import android.location.LocationProviderImpl; +import android.net.ConnectivityManager; import android.net.SntpClient; import android.os.Bundle; import android.os.IBinder; +import android.os.PowerManager; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.util.Config; import android.util.Log; +import android.util.SparseIntArray; +import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyIntents; @@ -50,9 +59,12 @@ import java.util.Properties; * * {@hide} */ -public class GpsLocationProvider extends LocationProviderImpl { +public class GpsLocationProvider extends ILocationProvider.Stub { private static final String TAG = "GpsLocationProvider"; + + private static final boolean DEBUG = true; + private static final boolean VERBOSE = false; /** * Broadcast intent action indicating that the GPS has either been @@ -97,6 +109,14 @@ public class GpsLocationProvider extends LocationProviderImpl { private static final int GPS_STATUS_ENGINE_ON = 3; private static final int GPS_STATUS_ENGINE_OFF = 4; + // these need to match GpsApgsStatusValue defines in gps.h + /** AGPS status event values. */ + private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; + private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; + private static final int GPS_AGPS_DATA_CONNECTED = 3; + private static final int GPS_AGPS_DATA_CONN_DONE = 4; + private static final int GPS_AGPS_DATA_CONN_FAILED = 5; + // these need to match GpsLocationFlags enum in gps.h private static final int LOCATION_INVALID = 0; private static final int LOCATION_HAS_LAT_LONG = 1; @@ -104,8 +124,8 @@ public class GpsLocationProvider extends LocationProviderImpl { private static final int LOCATION_HAS_SPEED = 4; private static final int LOCATION_HAS_BEARING = 8; private static final int LOCATION_HAS_ACCURACY = 16; - -// IMPORTANT - the GPS_DELETE_* symbols here must match constants in GpsLocationProvider.java + +// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h private static final int GPS_DELETE_EPHEMERIS = 0x0001; private static final int GPS_DELETE_ALMANAC = 0x0002; private static final int GPS_DELETE_POSITION = 0x0004; @@ -120,23 +140,36 @@ public class GpsLocationProvider extends LocationProviderImpl { private static final int GPS_DELETE_CELLDB_INFO = 0x8000; private static final int GPS_DELETE_ALL = 0xFFFF; + // these need to match AGpsType enum in gps.h + private static final int AGPS_TYPE_SUPL = 1; + private static final int AGPS_TYPE_C2K = 2; + + // for mAGpsDataConnectionState + private static final int AGPS_DATA_CONNECTION_CLOSED = 0; + private static final int AGPS_DATA_CONNECTION_OPENING = 1; + private static final int AGPS_DATA_CONNECTION_OPEN = 2; + private static final String PROPERTIES_FILE = "/etc/gps.conf"; private int mLocationFlags = LOCATION_INVALID; // current status - private int mStatus = TEMPORARILY_UNAVAILABLE; + private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE; // time for last status update private long mStatusUpdateTime = SystemClock.elapsedRealtime(); // turn off GPS fix icon if we haven't received a fix in 10 seconds - private static final long RECENT_FIX_TIMEOUT = 10 * 1000; + private static final long RECENT_FIX_TIMEOUT = 10; + + // number of fixes to receive before disabling GPS + private static final int MIN_FIX_COUNT = 10; + + // stop trying if we do not receive a fix within 60 seconds + private static final int NO_FIX_TIMEOUT = 60; // true if we are enabled private boolean mEnabled; - // true if we are enabled for location updates - private boolean mLocationTracking; // true if we have network connectivity private boolean mNetworkAvailable; @@ -147,6 +180,9 @@ public class GpsLocationProvider extends LocationProviderImpl { // requested frequency of fixes, in seconds private int mFixInterval = 1; + // number of fixes we have received since we started navigating + private int mFixCount; + private int mPositionMode = GPS_POSITION_MODE_STANDALONE; // true if we started navigation @@ -163,7 +199,8 @@ public class GpsLocationProvider extends LocationProviderImpl { private Properties mProperties; private String mNtpServer; - private Context mContext; + private final Context mContext; + private final ILocationManager mLocationManager; private Location mLocation = new Location(LocationManager.GPS_PROVIDER); private Bundle mLocationExtras = new Bundle(); private ArrayList mListeners = new ArrayList(); @@ -173,7 +210,27 @@ public class GpsLocationProvider extends LocationProviderImpl { private String mSuplHost; private int mSuplPort; + private String mC2KHost; + private int mC2KPort; private boolean mSetSuplServer; + private boolean mSetC2KServer; + private String mAGpsApn; + private int mAGpsDataConnectionState; + private final ConnectivityManager mConnMgr; + + // Wakelocks + private final static String WAKELOCK_KEY = "GpsLocationProvider"; + private final PowerManager.WakeLock mWakeLock; + + // Alarms + private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP"; + private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT"; + private final AlarmManager mAlarmManager; + private final PendingIntent mWakeupIntent; + private final PendingIntent mTimeoutIntent; + + private final IBatteryStats mBatteryStats; + private final SparseIntArray mClientUids = new SparseIntArray(); // how often to request NTP time, in milliseconds // current setting 4 hours @@ -182,13 +239,68 @@ public class GpsLocationProvider extends LocationProviderImpl { // current setting - 5 minutes private static final long RETRY_INTERVAL = 5*60*1000; - private ILocationCollector mCollector; + private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() { + public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException { + if (listener == null) { + throw new NullPointerException("listener is null in addGpsStatusListener"); + } + + synchronized(mListeners) { + IBinder binder = listener.asBinder(); + int size = mListeners.size(); + for (int i = 0; i < size; i++) { + Listener test = mListeners.get(i); + if (binder.equals(test.mListener.asBinder())) { + // listener already added + return; + } + } + + Listener l = new Listener(listener); + binder.linkToDeath(l, 0); + mListeners.add(l); + } + } + + public void removeGpsStatusListener(IGpsStatusListener listener) { + if (listener == null) { + throw new NullPointerException("listener is null in addGpsStatusListener"); + } + + synchronized(mListeners) { + IBinder binder = listener.asBinder(); + Listener l = null; + int size = mListeners.size(); + for (int i = 0; i < size && l == null; i++) { + Listener test = mListeners.get(i); + if (binder.equals(test.mListener.asBinder())) { + l = test; + } + } + + if (l != null) { + mListeners.remove(l); + binder.unlinkToDeath(l, 0); + } + } + } + }; + + public IGpsStatusProvider getGpsStatusProvider() { + return mGpsStatusProvider; + } - private class TelephonyBroadcastReceiver extends BroadcastReceiver { + private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { + if (action.equals(ALARM_WAKEUP)) { + if (DEBUG) Log.d(TAG, "ALARM_WAKEUP"); + startNavigating(); + } else if (action.equals(ALARM_TIMEOUT)) { + if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT"); + hibernate(); + } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { String state = intent.getStringExtra(Phone.STATE_KEY); String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); @@ -196,27 +308,44 @@ public class GpsLocationProvider extends LocationProviderImpl { if (Config.LOGD) { Log.d(TAG, "state: " + state + " apnName: " + apnName + " reason: " + reason); } - if ("CONNECTED".equals(state)) { - native_set_supl_apn(apnName); - } else { - native_set_supl_apn(""); + // FIXME - might not have an APN on CDMA + if ("CONNECTED".equals(state) && apnName != null && apnName.length() > 0) { + mAGpsApn = apnName; + if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { + native_agps_data_conn_open(mAGpsApn); + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; + } } } } - } + }; public static boolean isSupported() { return native_is_supported(); } - public GpsLocationProvider(Context context) { - super(LocationManager.GPS_PROVIDER); + public GpsLocationProvider(Context context, ILocationManager locationManager) { mContext = context; + mLocationManager = locationManager; + + // Create a wake lock + PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); + + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); + mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); - TelephonyBroadcastReceiver receiver = new TelephonyBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ALARM_WAKEUP); + intentFilter.addAction(ALARM_TIMEOUT); intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - context.registerReceiver(receiver, intentFilter); + context.registerReceiver(mBroadcastReciever, intentFilter); + + mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + + // Battery statistics service to be notified when GPS turns on or off + mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); mProperties = new Properties(); try { @@ -225,14 +354,26 @@ public class GpsLocationProvider extends LocationProviderImpl { mProperties.load(stream); stream.close(); mNtpServer = mProperties.getProperty("NTP_SERVER", null); + mSuplHost = mProperties.getProperty("SUPL_HOST"); - String suplPortString = mProperties.getProperty("SUPL_PORT"); - if (mSuplHost != null && suplPortString != null) { + String portString = mProperties.getProperty("SUPL_PORT"); + if (mSuplHost != null && portString != null) { try { - mSuplPort = Integer.parseInt(suplPortString); + mSuplPort = Integer.parseInt(portString); mSetSuplServer = true; } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse SUPL_PORT: " + suplPortString); + Log.e(TAG, "unable to parse SUPL_PORT: " + portString); + } + } + + mC2KHost = mProperties.getProperty("C2K_HOST"); + portString = mProperties.getProperty("C2K_PORT"); + if (mC2KHost != null && portString != null) { + try { + mC2KPort = Integer.parseInt(portString); + mSetC2KServer = true; + } catch (NumberFormatException e) { + Log.e(TAG, "unable to parse C2K_PORT: " + portString); } } } catch (IOException e) { @@ -240,19 +381,15 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - public void setLocationCollector(ILocationCollector collector) { - mCollector = collector; - } - /** * Returns true if the provider requires access to a * data network (e.g., the Internet), false otherwise. */ - @Override public boolean requiresNetwork() { // We want updateNetworkState() to get called when the network state changes // for XTRA and NTP time injection support. - return (mNtpServer != null || native_supports_xtra() || mSuplHost != null); + return (mNtpServer != null || native_supports_xtra() || + mSuplHost != null || mC2KHost != null); } public void updateNetworkState(int state) { @@ -273,7 +410,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * satellite-based positioning system (e.g., GPS), false * otherwise. */ - @Override public boolean requiresSatellite() { return true; } @@ -283,7 +419,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * cellular network (e.g., to make use of cell tower IDs), false * otherwise. */ - @Override public boolean requiresCell() { return false; } @@ -293,7 +428,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * monetary charge to the user, false if use is free. It is up to * each provider to give accurate information. */ - @Override public boolean hasMonetaryCost() { return false; } @@ -304,7 +438,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * under most circumstances but may occassionally not report it * should return true. */ - @Override public boolean supportsAltitude() { return true; } @@ -315,7 +448,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * under most circumstances but may occassionally not report it * should return true. */ - @Override public boolean supportsSpeed() { return true; } @@ -326,7 +458,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * under most circumstances but may occassionally not report it * should return true. */ - @Override public boolean supportsBearing() { return true; } @@ -337,7 +468,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * @return the power requirement for this provider, as one of the * constants Criteria.POWER_REQUIREMENT_*. */ - @Override public int getPowerRequirement() { return Criteria.POWER_HIGH; } @@ -348,17 +478,15 @@ public class GpsLocationProvider extends LocationProviderImpl { * @return the accuracy of location from this provider, as one * of the constants Criteria.ACCURACY_*. */ - @Override public int getAccuracy() { return Criteria.ACCURACY_FINE; } /** * Enables this provider. When enabled, calls to getStatus() - * and getLocation() must be handled. Hardware may be started up + * must be handled. Hardware may be started up * when the provider is enabled. */ - @Override public synchronized void enable() { if (Config.LOGD) Log.d(TAG, "enable"); if (mEnabled) return; @@ -385,10 +513,9 @@ public class GpsLocationProvider extends LocationProviderImpl { /** * Disables this provider. When disabled, calls to getStatus() - * and getLocation() need not be handled. Hardware may be shut + * need not be handled. Hardware may be shut * down while the provider is disabled. */ - @Override public synchronized void disable() { if (Config.LOGD) Log.d(TAG, "disable"); if (!mEnabled) return; @@ -412,15 +539,19 @@ public class GpsLocationProvider extends LocationProviderImpl { mNetworkThread = null; } + // The GpsEventThread does not wait for the GPS to shutdown + // so we need to report the GPS_STATUS_ENGINE_OFF event here + if (mNavigating) { + reportStatus(GPS_STATUS_ENGINE_OFF); + } + native_cleanup(); } - @Override public boolean isEnabled() { return mEnabled; } - @Override public int getStatus(Bundle extras) { if (extras != null) { extras.putInt("satellites", mSvCount); @@ -437,49 +568,23 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - @Override public long getStatusUpdateTime() { return mStatusUpdateTime; } - @Override - public boolean getLocation(Location l) { - synchronized (mLocation) { - // don't report locations without latitude and longitude - if ((mLocationFlags & LOCATION_HAS_LAT_LONG) == 0) { - return false; - } - l.set(mLocation); - l.setExtras(mLocationExtras); - return true; - } - } - - @Override public void enableLocationTracking(boolean enable) { - if (mLocationTracking == enable) { - return; - } - if (enable) { - mFixRequestTime = System.currentTimeMillis(); mTTFF = 0; mLastFixTime = 0; startNavigating(); } else { + mAlarmManager.cancel(mWakeupIntent); + mAlarmManager.cancel(mTimeoutIntent); stopNavigating(); } - mLocationTracking = enable; - } - - @Override - public boolean isLocationTracking() { - return mLocationTracking; } - @Override public void setMinTime(long minTime) { - super.setMinTime(minTime); if (Config.LOGD) Log.d(TAG, "setMinTime " + minTime); if (minTime >= 0) { @@ -488,7 +593,6 @@ public class GpsLocationProvider extends LocationProviderImpl { interval = 1; } mFixInterval = interval; - native_set_fix_frequency(mFixInterval); } } @@ -510,48 +614,28 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException { - if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener"); - - synchronized(mListeners) { - IBinder binder = listener.asBinder(); - int size = mListeners.size(); - for (int i = 0; i < size; i++) { - Listener test = mListeners.get(i); - if (binder.equals(test.mListener.asBinder())) { - // listener already added - return; - } + public void addListener(int uid) { + mClientUids.put(uid, 0); + if (mNavigating) { + try { + mBatteryStats.noteStartGps(uid); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException in addListener"); } - - Listener l = new Listener(listener); - binder.linkToDeath(l, 0); - mListeners.add(l); } } - - public void removeGpsStatusListener(IGpsStatusListener listener) { - if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener"); - synchronized(mListeners) { - IBinder binder = listener.asBinder(); - Listener l = null; - int size = mListeners.size(); - for (int i = 0; i < size && l == null; i++) { - Listener test = mListeners.get(i); - if (binder.equals(test.mListener.asBinder())) { - l = test; - } - } - - if (l != null) { - mListeners.remove(l); - binder.unlinkToDeath(l, 0); + public void removeListener(int uid) { + mClientUids.delete(uid); + if (mNavigating) { + try { + mBatteryStats.noteStopGps(uid); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException in removeListener"); } } } - @Override public boolean sendExtraCommand(String command, Bundle extras) { if ("delete_aiding_data".equals(command)) { @@ -594,20 +678,29 @@ public class GpsLocationProvider extends LocationProviderImpl { public void startNavigating() { if (!mStarted) { - if (Config.LOGV) Log.v(TAG, "startNavigating"); + if (DEBUG) Log.d(TAG, "startNavigating"); mStarted = true; if (!native_start(mPositionMode, false, mFixInterval)) { mStarted = false; Log.e(TAG, "native_start failed in startNavigating()"); + return; } // reset SV count to zero - updateStatus(TEMPORARILY_UNAVAILABLE, 0); + updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); + mFixCount = 0; + mFixRequestTime = System.currentTimeMillis(); + // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT + // and our fix interval is not short + if (mFixInterval >= NO_FIX_TIMEOUT) { + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT * 1000, mTimeoutIntent); + } } } public void stopNavigating() { - if (Config.LOGV) Log.v(TAG, "stopNavigating"); + if (DEBUG) Log.d(TAG, "stopNavigating"); if (mStarted) { mStarted = false; native_stop(); @@ -616,16 +709,27 @@ public class GpsLocationProvider extends LocationProviderImpl { mLocationFlags = LOCATION_INVALID; // reset SV count to zero - updateStatus(TEMPORARILY_UNAVAILABLE, 0); + updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); } } + private void hibernate() { + // stop GPS until our next fix interval arrives + stopNavigating(); + mFixCount = 0; + mAlarmManager.cancel(mTimeoutIntent); + mAlarmManager.cancel(mWakeupIntent); + long now = SystemClock.elapsedRealtime(); + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + mFixInterval * 1000, mWakeupIntent); + } + /** * called from native code to update our position. */ private void reportLocation(int flags, double latitude, double longitude, double altitude, float speed, float bearing, float accuracy, long timestamp) { - if (Config.LOGV) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + + if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + " timestamp: " + timestamp); mLastFixTime = System.currentTimeMillis(); @@ -679,19 +783,25 @@ public class GpsLocationProvider extends LocationProviderImpl { mLocation.removeAccuracy(); } - // Send to collector - if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG - && mCollector != null) { - mCollector.updateLocation(mLocation); + try { + mLocationManager.reportLocation(mLocation); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling reportLocation"); } } - if (mStarted && mStatus != AVAILABLE) { + if (mStarted && mStatus != LocationProvider.AVAILABLE) { + mAlarmManager.cancel(mTimeoutIntent); // send an intent to notify that the GPS is receiving fixes. Intent intent = new Intent(GPS_FIX_CHANGE_ACTION); intent.putExtra(EXTRA_ENABLED, true); mContext.sendBroadcast(intent); - updateStatus(AVAILABLE, mSvCount); + updateStatus(LocationProvider.AVAILABLE, mSvCount); + } + + if (mFixCount++ >= MIN_FIX_COUNT && mFixInterval > 1) { + if (DEBUG) Log.d(TAG, "exceeded MIN_FIX_COUNT"); + hibernate(); } } @@ -699,12 +809,16 @@ public class GpsLocationProvider extends LocationProviderImpl { * called from native code to update our status */ private void reportStatus(int status) { - if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status); + if (VERBOSE) Log.v(TAG, "reportStatus status: " + status); boolean wasNavigating = mNavigating; mNavigating = (status == GPS_STATUS_SESSION_BEGIN); if (wasNavigating != mNavigating) { + if (mNavigating) { + if (DEBUG) Log.d(TAG, "Acquiring wakelock"); + mWakeLock.acquire(); + } synchronized(mListeners) { int size = mListeners.size(); for (int i = 0; i < size; i++) { @@ -724,10 +838,29 @@ public class GpsLocationProvider extends LocationProviderImpl { } } + try { + // update battery stats + for (int i=mClientUids.size() - 1; i >= 0; i--) { + int uid = mClientUids.keyAt(i); + if (mNavigating) { + mBatteryStats.noteStartGps(uid); + } else { + mBatteryStats.noteStopGps(uid); + } + } + } catch (RemoteException e) { + Log.w(TAG, "RemoteException in reportStatus"); + } + // send an intent to notify that the GPS has been enabled or disabled. Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION); intent.putExtra(EXTRA_ENABLED, mNavigating); mContext.sendBroadcast(intent); + + if (!mNavigating) { + if (DEBUG) Log.d(TAG, "Releasing wakelock"); + mWakeLock.release(); + } } } @@ -755,12 +888,12 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - if (Config.LOGD) { - if (Config.LOGV) Log.v(TAG, "SV count: " + svCount + + if (VERBOSE) { + Log.v(TAG, "SV count: " + svCount + " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); for (int i = 0; i < svCount; i++) { - if (Config.LOGV) Log.v(TAG, "sv: " + mSvs[i] + + Log.v(TAG, "sv: " + mSvs[i] + " snr: " + (float)mSnrs[i]/10 + " elev: " + mSvElevations[i] + " azimuth: " + mSvAzimuths[i] + @@ -772,16 +905,53 @@ public class GpsLocationProvider extends LocationProviderImpl { updateStatus(mStatus, svCount); - if (mNavigating && mStatus == AVAILABLE && mLastFixTime > 0 && - System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { + if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && + System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT * 1000) { // send an intent to notify that the GPS is no longer receiving fixes. Intent intent = new Intent(GPS_FIX_CHANGE_ACTION); intent.putExtra(EXTRA_ENABLED, false); mContext.sendBroadcast(intent); - updateStatus(TEMPORARILY_UNAVAILABLE, mSvCount); + updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); } } - + + /** + * called from native code to update AGPS status + */ + private void reportAGpsStatus(int type, int status) { + switch (status) { + case GPS_REQUEST_AGPS_DATA_CONN: + int result = mConnMgr.startUsingNetworkFeature( + ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); + if (result == Phone.APN_ALREADY_ACTIVE) { + native_agps_data_conn_open(mAGpsApn); + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; + } else if (result == Phone.APN_REQUEST_STARTED) { + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; + } else { + native_agps_data_conn_failed(); + } + break; + case GPS_RELEASE_AGPS_DATA_CONN: + if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { + mConnMgr.stopUsingNetworkFeature( + ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); + native_agps_data_conn_closed(); + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; + } + break; + case GPS_AGPS_DATA_CONNECTED: + // Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); + break; + case GPS_AGPS_DATA_CONN_DONE: + // Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); + break; + case GPS_AGPS_DATA_CONN_FAILED: + // Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); + break; + } + } + private void xtraDownloadRequest() { if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest"); if (mNetworkThread != null) { @@ -789,6 +959,29 @@ public class GpsLocationProvider extends LocationProviderImpl { } } + private boolean setAGpsServer(int type, String host, int port) { + try { + InetAddress inetAddress = InetAddress.getByName(host); + if (inetAddress != null) { + byte[] addrBytes = inetAddress.getAddress(); + long addr = 0; + for (int i = 0; i < addrBytes.length; i++) { + int temp = addrBytes[i]; + // signed -> unsigned + if (temp < 0) temp = 256 + temp; + addr = addr * 256 + temp; + } + // use MS-Based position mode if SUPL support is enabled + mPositionMode = GPS_POSITION_MODE_MS_BASED; + native_set_agps_server(type, (int)addr, port); + } + } catch (UnknownHostException e) { + Log.e(TAG, "unknown host for server " + host); + return false; + } + return true; + } + private class GpsEventThread extends Thread { public GpsEventThread() { @@ -797,8 +990,8 @@ public class GpsLocationProvider extends LocationProviderImpl { public void run() { if (Config.LOGD) Log.d(TAG, "GpsEventThread starting"); - // thread exits after disable() is called and navigation has stopped - while (mEnabled || mNavigating) { + // Exit as soon as disable() is called instead of waiting for the GPS to stop. + while (mEnabled) { // this will wait for an event from the GPS, // which will be reported via reportLocation or reportStatus native_wait_for_event(); @@ -860,7 +1053,8 @@ public class GpsLocationProvider extends LocationProviderImpl { } } waitTime = getWaitTime(); - } while (!mDone && ((!mXtraDownloadRequested && !mSetSuplServer && waitTime > 0) + } while (!mDone && ((!mXtraDownloadRequested && + !mSetSuplServer && !mSetC2KServer && waitTime > 0) || !mNetworkAvailable)); if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop"); @@ -887,26 +1081,15 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - // Set the SUPL server address if we have not yet + // Set the AGPS server addresses if we have not yet if (mSetSuplServer) { - try { - InetAddress inetAddress = InetAddress.getByName(mSuplHost); - if (inetAddress != null) { - byte[] addrBytes = inetAddress.getAddress(); - long addr = 0; - for (int i = 0; i < addrBytes.length; i++) { - int temp = addrBytes[i]; - // signed -> unsigned - if (temp < 0) temp = 256 + temp; - addr = addr * 256 + temp; - } - // use MS-Based position mode if SUPL support is enabled - mPositionMode = GPS_POSITION_MODE_MS_BASED; - native_set_supl_server((int)addr, mSuplPort); - mSetSuplServer = false; - } - } catch (UnknownHostException e) { - Log.e(TAG, "unknown host for SUPL server " + mSuplHost); + if (setAGpsServer(AGPS_TYPE_SUPL, mSuplHost, mSuplPort)) { + mSetSuplServer = false; + } + } + if (mSetC2KServer) { + if (setAGpsServer(AGPS_TYPE_C2K, mC2KHost, mC2KPort)) { + mSetC2KServer = false; } } @@ -1000,7 +1183,9 @@ public class GpsLocationProvider extends LocationProviderImpl { private native boolean native_supports_xtra(); private native void native_inject_xtra_data(byte[] data, int length); - // SUPL Support - private native void native_set_supl_server(int addr, int port); - private native void native_set_supl_apn(String apn); + // AGPS Support + private native void native_agps_data_conn_open(String apn); + private native void native_agps_data_conn_closed(); + private native void native_agps_data_conn_failed(); + private native void native_set_agps_server(int type, int addr, int port); } diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/location/java/com/android/internal/location/GpsXtraDownloader.java index b8545a695d41914b7683f391a46fa9d9fc39bf0b..2a8be5732f6ed23a452a531eb2b2b726ca7d1381 100644 --- a/location/java/com/android/internal/location/GpsXtraDownloader.java +++ b/location/java/com/android/internal/location/GpsXtraDownloader.java @@ -70,11 +70,11 @@ public class GpsXtraDownloader { if (server1 != null) mXtraServers[count++] = server1; if (server2 != null) mXtraServers[count++] = server2; if (server3 != null) mXtraServers[count++] = server3; - } - - // randomize first server - Random random = new Random(); - mNextServerIndex = random.nextInt(count); + + // randomize first server + Random random = new Random(); + mNextServerIndex = random.nextInt(count); + } } byte[] downloadXtraData() { diff --git a/location/java/com/android/internal/location/ILocationCollector.java b/location/java/com/android/internal/location/ILocationCollector.java deleted file mode 100644 index 8a7cdcce1ed39695028ebf06423547c21b3ce602..0000000000000000000000000000000000000000 --- a/location/java/com/android/internal/location/ILocationCollector.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.location; - -import android.location.Location; -import android.net.wifi.ScanResult; - -import com.android.internal.location.CellState; - -import java.util.List; - -/** - * Listens for GPS and cell/wifi changes and anonymously uploads to server for - * improving quality of service of NetworkLocationProvider. This service is only enabled when - * the user has enabled the network location provider. - * - * {@hide} - */ -public interface ILocationCollector { - /** - * Updates GPS location if collection is enabled - * - * @param location location object - */ - abstract public void updateLocation(Location location); - - /** - * Updates wifi scan results if collection is enabled - * - * @param currentScanResults scan results - */ - abstract public void updateWifiScanResults(List currentScanResults); - - /** - * Updates the status of the network location provider. - * - * @param enabled true if user has enabled network location based on Google's database - * of wifi points and cell towers. - */ - abstract public void updateNetworkProviderStatus(boolean enabled); - - /** - * Updates cell tower state. This is usually always up to date so should be uploaded - * each time a new location is available. - * - * @param newState cell state - */ - abstract public void updateCellState(CellState newState); - - /** - * Updates the battery health. Battery level is healthy if there is greater than - * {@link #MIN_BATTERY_LEVEL} percentage left or if the device is plugged in - * - * @param scale maximum scale for battery - * @param level current level - * @param plugged true if device is plugged in - */ - abstract public void updateBatteryState(int scale, int level, boolean plugged); -} diff --git a/location/java/com/android/internal/location/INetworkLocationProvider.java b/location/java/com/android/internal/location/INetworkLocationProvider.java deleted file mode 100644 index 730cb480a4d6ca10650fcf43a014c377271103fc..0000000000000000000000000000000000000000 --- a/location/java/com/android/internal/location/INetworkLocationProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.location; - -import android.location.Address; -import android.location.Location; -import android.net.wifi.ScanResult; - -import com.google.common.io.protocol.ProtoBuf; - -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Locale; - -/** - * Interface for network location provider - * - * {@hide} - */ -public interface INetworkLocationProvider { - - public interface Callback { - - /** - * Callback function to notify of a received network location - * - * @param location location object that is received. may be null if not a valid location - * @param successful true if network query was successful, even if no location was found - */ - void locationReceived(Location location, boolean successful); - } - - /** - * Updates the current cell lock status. - * - * @param acquired true if a cell lock has been acquired - */ - abstract public void updateCellLockStatus(boolean acquired); - - /** - * Notifies the provider if Wifi has been enabled or disabled - * by the user - * - * @param enabled true if wifi is enabled; false otherwise - */ - abstract public void updateWifiEnabledState(boolean enabled); - - /** - * Notifies the provider that there are scan results available. - * - * @param scanResults list of wifi scan results - */ - abstract public void updateWifiScanResults(List scanResults); - - /** - * Adds a list of application clients - * Only used by the NetworkLocationProvider - * - * @param applications list of package names - */ - abstract public void addListener(String[] applications); - - /** - * Removes a list of application clients - * Only used by the NetworkLocationProvider - * - * @param applications list of package names - */ - abstract public void removeListener(String[] applications); - - - abstract public String getFromLocation(double latitude, double longitude, int maxResults, - String language, String country, String variant, String appName, List

          addrs); - - abstract public String getFromLocationName(String locationName, - double lowerLeftLatitude, double lowerLeftLongitude, - double upperRightLatitude, double upperRightLongitude, int maxResults, - String language, String country, String variant, String appName, List
          addrs); - -} diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..b40cdcaf212f0bcc2ecb631015bd58e7372fc2c0 --- /dev/null +++ b/location/java/com/android/internal/location/LocationProviderProxy.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.location; + +import android.location.Address; +import android.location.ILocationProvider; +import android.location.Location; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.List; + +/** + * A class for proxying remote ILocationProvider implementations. + * + * {@hide} + */ +public class LocationProviderProxy implements IBinder.DeathRecipient { + + private static final String TAG = "LocationProviderProxy"; + + private final String mName; + private final ILocationProvider mProvider; + private boolean mLocationTracking = false; + private long mMinTime = 0; + private boolean mDead; + + public LocationProviderProxy(String name, ILocationProvider provider) { + mName = name; + mProvider = provider; + try { + provider.asBinder().linkToDeath(this, 0); + } catch (RemoteException e) { + Log.e(TAG, "linkToDeath failed", e); + mDead = true; + } + } + + public String getName() { + return mName; + } + + public boolean isDead() { + return mDead; + } + + public boolean requiresNetwork() { + try { + return mProvider.requiresNetwork(); + } catch (RemoteException e) { + Log.e(TAG, "requiresNetwork failed", e); + return false; + } + } + + public boolean requiresSatellite() { + try { + return mProvider.requiresSatellite(); + } catch (RemoteException e) { + Log.e(TAG, "requiresSatellite failed", e); + return false; + } + } + + public boolean requiresCell() { + try { + return mProvider.requiresCell(); + } catch (RemoteException e) { + Log.e(TAG, "requiresCell failed", e); + return false; + } + } + + public boolean hasMonetaryCost() { + try { + return mProvider.hasMonetaryCost(); + } catch (RemoteException e) { + Log.e(TAG, "hasMonetaryCost failed", e); + return false; + } + } + + public boolean supportsAltitude() { + try { + return mProvider.supportsAltitude(); + } catch (RemoteException e) { + Log.e(TAG, "supportsAltitude failed", e); + return false; + } + } + + public boolean supportsSpeed() { + try { + return mProvider.supportsSpeed(); + } catch (RemoteException e) { + Log.e(TAG, "supportsSpeed failed", e); + return false; + } + } + + public boolean supportsBearing() { + try { + return mProvider.supportsBearing(); + } catch (RemoteException e) { + Log.e(TAG, "supportsBearing failed", e); + return false; + } + } + + public int getPowerRequirement() { + try { + return mProvider.getPowerRequirement(); + } catch (RemoteException e) { + Log.e(TAG, "getPowerRequirement failed", e); + return 0; + } + } + + public int getAccuracy() { + try { + return mProvider.getAccuracy(); + } catch (RemoteException e) { + Log.e(TAG, "getAccuracy failed", e); + return 0; + } + } + + public void enable() { + try { + mProvider.enable(); + } catch (RemoteException e) { + Log.e(TAG, "enable failed", e); + } + } + + public void disable() { + try { + mProvider.disable(); + } catch (RemoteException e) { + Log.e(TAG, "disable failed", e); + } + } + + public boolean isEnabled() { + try { + return mProvider.isEnabled(); + } catch (RemoteException e) { + Log.e(TAG, "isEnabled failed", e); + return false; + } + } + + public int getStatus(Bundle extras) { + try { + return mProvider.getStatus(extras); + } catch (RemoteException e) { + Log.e(TAG, "getStatus failed", e); + return 0; + } + } + + public long getStatusUpdateTime() { + try { + return mProvider.getStatusUpdateTime(); + } catch (RemoteException e) { + Log.e(TAG, "getStatusUpdateTime failed", e); + return 0; + } + } + + public boolean isLocationTracking() { + return mLocationTracking; + } + + public void enableLocationTracking(boolean enable) { + mLocationTracking = enable; + try { + mProvider.enableLocationTracking(enable); + } catch (RemoteException e) { + Log.e(TAG, "enableLocationTracking failed", e); + } + } + + public long getMinTime() { + return mMinTime; + } + + public void setMinTime(long minTime) { + mMinTime = minTime; + try { + mProvider.setMinTime(minTime); + } catch (RemoteException e) { + Log.e(TAG, "setMinTime failed", e); + } + } + + public void updateNetworkState(int state) { + try { + mProvider.updateNetworkState(state); + } catch (RemoteException e) { + Log.e(TAG, "updateNetworkState failed", e); + } + } + + public boolean sendExtraCommand(String command, Bundle extras) { + try { + return mProvider.sendExtraCommand(command, extras); + } catch (RemoteException e) { + Log.e(TAG, "sendExtraCommand failed", e); + return false; + } + } + + public void addListener(int uid) { + try { + mProvider.addListener(uid); + } catch (RemoteException e) { + Log.e(TAG, "addListener failed", e); + } + } + + public void removeListener(int uid) { + try { + mProvider.removeListener(uid); + } catch (RemoteException e) { + Log.e(TAG, "removeListener failed", e); + } + } + + public void binderDied() { + Log.w(TAG, "Location Provider " + mName + " died"); + mDead = true; + } +} diff --git a/location/java/com/android/internal/location/MockProvider.java b/location/java/com/android/internal/location/MockProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..f167a44f2ce81d76e2d5fe5f5270e456b701dc5e --- /dev/null +++ b/location/java/com/android/internal/location/MockProvider.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.location; + +import android.location.ILocationManager; +import android.location.ILocationProvider; +import android.location.Location; +import android.location.LocationProvider; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; +import android.util.PrintWriterPrinter; + +import java.io.PrintWriter; + +/** + * A mock location provider used by LocationManagerService to implement test providers. + * + * {@hide} + */ +public class MockProvider extends ILocationProvider.Stub { + private final String mName; + private final ILocationManager mLocationManager; + private final boolean mRequiresNetwork; + private final boolean mRequiresSatellite; + private final boolean mRequiresCell; + private final boolean mHasMonetaryCost; + private final boolean mSupportsAltitude; + private final boolean mSupportsSpeed; + private final boolean mSupportsBearing; + private final int mPowerRequirement; + private final int mAccuracy; + private final Location mLocation; + private int mStatus; + private long mStatusUpdateTime; + private final Bundle mExtras = new Bundle(); + private boolean mHasLocation; + private boolean mHasStatus; + private boolean mEnabled; + + private static final String TAG = "MockProvider"; + + public MockProvider(String name, ILocationManager locationManager, + boolean requiresNetwork, boolean requiresSatellite, + boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, + boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { + mName = name; + mLocationManager = locationManager; + mRequiresNetwork = requiresNetwork; + mRequiresSatellite = requiresSatellite; + mRequiresCell = requiresCell; + mHasMonetaryCost = hasMonetaryCost; + mSupportsAltitude = supportsAltitude; + mSupportsBearing = supportsBearing; + mSupportsSpeed = supportsSpeed; + mPowerRequirement = powerRequirement; + mAccuracy = accuracy; + mLocation = new Location(name); + } + + public void disable() { + mEnabled = false; + } + + public void enable() { + mEnabled = true; + } + + public int getStatus(Bundle extras) { + if (mHasStatus) { + extras.clear(); + extras.putAll(mExtras); + return mStatus; + } else { + return LocationProvider.AVAILABLE; + } + } + + public long getStatusUpdateTime() { + return mStatusUpdateTime; + } + + public boolean isEnabled() { + return mEnabled; + } + + public int getAccuracy() { + return mAccuracy; + } + + public int getPowerRequirement() { + return mPowerRequirement; + } + + public boolean hasMonetaryCost() { + return mHasMonetaryCost; + } + + public boolean requiresCell() { + return mRequiresCell; + } + + public boolean requiresNetwork() { + return mRequiresNetwork; + } + + public boolean requiresSatellite() { + return mRequiresSatellite; + } + + public boolean supportsAltitude() { + return mSupportsAltitude; + } + + public boolean supportsBearing() { + return mSupportsBearing; + } + + public boolean supportsSpeed() { + return mSupportsSpeed; + } + + public void setLocation(Location l) { + mLocation.set(l); + mHasLocation = true; + try { + mLocationManager.reportLocation(mLocation); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling reportLocation"); + } + } + + public void clearLocation() { + mHasLocation = false; + } + + public void setStatus(int status, Bundle extras, long updateTime) { + mStatus = status; + mStatusUpdateTime = updateTime; + mExtras.clear(); + if (extras != null) { + mExtras.putAll(extras); + } + mHasStatus = true; + } + + public void clearStatus() { + mHasStatus = false; + mStatusUpdateTime = 0; + } + + public void enableLocationTracking(boolean enable) { + } + + public void setMinTime(long minTime) { + } + + public void updateNetworkState(int state) { + } + + public boolean sendExtraCommand(String command, Bundle extras) { + return false; + } + + public void addListener(int uid) { + } + + public void removeListener(int uid) { + } + + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + mName); + pw.println(prefix + "mHasLocation=" + mHasLocation); + pw.println(prefix + "mLocation:"); + mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); + pw.println(prefix + "mHasStatus=" + mHasStatus); + pw.println(prefix + "mStatus=" + mStatus); + pw.println(prefix + "mStatusUpdateTime=" + mStatusUpdateTime); + pw.println(prefix + "mExtras=" + mExtras); + } +} diff --git a/location/java/com/android/internal/location/TrackProvider.java b/location/java/com/android/internal/location/TrackProvider.java deleted file mode 100644 index 545d7dc8927413e5637cd4aefede6c008ed73c2a..0000000000000000000000000000000000000000 --- a/location/java/com/android/internal/location/TrackProvider.java +++ /dev/null @@ -1,720 +0,0 @@ -// Copyright 2007 The Android Open Source Project - -package com.android.internal.location; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; - -import android.location.Criteria; -import android.location.Location; -import android.location.LocationProviderImpl; -import android.os.Bundle; -import android.util.Config; -import android.util.Log; - -/** - * A dummy provider that returns positions interpolated from a sequence - * of caller-supplied waypoints. The waypoints are supplied as a - * String containing one or more numeric quadruples of the form: - *
          - * - * - * - *

          The waypoints must be supplied in increasing timestamp order. - * - *

          The time at which the provider is constructed is considered to - * be time 0, and further requests for positions will return a - * position that is linearly interpolated between the waypoints whose - * timestamps are closest to the amount of wall clock time that has - * elapsed since time 0. - * - *

          Following the time of the last waypoint, the position of that - * waypoint will continue to be returned indefinitely. - * - * {@hide} - */ -public class TrackProvider extends LocationProviderImpl { - static final String LOG_TAG = "TrackProvider"; - - private static final long INTERVAL = 1000L; - - private boolean mEnabled = true; - - private double mLatitude; - private double mLongitude; - private boolean mHasAltitude; - private boolean mHasBearing; - private boolean mHasSpeed; - private double mAltitude; - private float mBearing; - private float mSpeed; - private Bundle mExtras; - - private long mBaseTime; - private long mLastTime = -1L; - private long mTime; - - private long mMinTime; - private long mMaxTime; - - private List mWaypoints = new ArrayList(); - private int mWaypointIndex = 0; - - private boolean mRequiresNetwork = false; - private boolean mRequiresSatellite = false; - private boolean mRequiresCell = false; - private boolean mHasMonetaryCost = false; - private boolean mSupportsAltitude = true; - private boolean mSupportsSpeed = true; - private boolean mSupportsBearing = true; - private boolean mRepeat = false; - private int mPowerRequirement = Criteria.POWER_LOW; - private int mAccuracy = Criteria.ACCURACY_COARSE; - - private float mTrackSpeed = 100.0f; // km/hr - default for kml tracks - - private Location mInitialLocation; - - private void close(Reader rdr) { - try { - if (rdr != null) { - rdr.close(); - } - } catch (IOException e) { - Log.w(LOG_TAG, "Exception closing reader", e); - } - } - - public void readTrack(File trackFile) { - BufferedReader br = null; - try { - br = new BufferedReader(new FileReader(trackFile), 8192); - String s; - - long lastTime = -Long.MAX_VALUE; - while ((s = br.readLine()) != null) { - String[] tokens = s.split("\\s+"); - if (tokens.length != 4 && tokens.length != 6) { - Log.e(LOG_TAG, "Got track \"" + s + - "\", wanted

          Upon creation, an AudioRecord object initializes its associated audio buffer that it will * fill with the new audio data. The size of this buffer, specified during the construction, * determines how long an AudioRecord can record before "over-running" data that has not - * been read yet. Data should be from the audio hardware in chunks of sizes inferior to + * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to * the total recording buffer size. */ public class AudioRecord @@ -49,20 +49,20 @@ public class AudioRecord // Constants //-------------------- /** - * State of an AudioRecord that was not successfully initialized upon creation + * indicates AudioRecord state is not successfully initialized. */ public static final int STATE_UNINITIALIZED = 0; /** - * State of an AudioRecord that is ready to be used + * indicates AudioRecord state is ready to be used */ public static final int STATE_INITIALIZED = 1; /** - * State of an AudioRecord this is not recording + * indicates AudioRecord recording state is not recording */ public static final int RECORDSTATE_STOPPED = 1; // matches SL_RECORDSTATE_STOPPED /** - * State of an AudioRecord this is recording + * indicates AudioRecord recording state is recording */ public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING @@ -94,11 +94,11 @@ public class AudioRecord // Events: // to keep in sync with frameworks/base/include/media/AudioRecord.h /** - * Event id for when the recording head has reached a previously set marker. + * Event id denotes when record head has reached a previously set marker. */ private static final int NATIVE_EVENT_MARKER = 2; /** - * Event id for when the previously set update period has passed during recording. + * Event id denotes when previously set update period has elapsed during recording. */ private static final int NATIVE_EVENT_NEW_POS = 3; @@ -188,7 +188,7 @@ public class AudioRecord */ private int mNativeBufferSizeInBytes = 0; - + //--------------------------------------------------------- // Constructor, Finalize //-------------------- @@ -206,7 +206,9 @@ public class AudioRecord * {@link AudioFormat#ENCODING_PCM_8BIT} * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written * to during the recording. New audio data can be read from this buffer in smaller chunks - * than this size. + * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum + * required buffer size for the successful creation of an AudioRecord instance. Using values + * smaller than getMinBufferSize() will result in an initialization failure. * @throws java.lang.IllegalArgumentException */ public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, @@ -319,11 +321,13 @@ public class AudioRecord mNativeBufferSizeInBytes = audioBufferSize; } - - + + /** * Releases the native AudioRecord resources. + * The object can no longer be used and the reference should be set to null + * after a call to release() */ public void release() { try { @@ -334,7 +338,7 @@ public class AudioRecord native_release(); mState = STATE_UNINITIALIZED; } - + @Override protected void finalize() { @@ -404,24 +408,27 @@ public class AudioRecord public int getRecordingState() { return mRecordingState; } - + /** - * @return marker position in frames + * Returns the notification marker position expressed in frames. */ public int getNotificationMarkerPosition() { return native_get_marker_pos(); } /** - * @return update period in frames + * Returns the notification update period expressed in frames. */ public int getPositionNotificationPeriod() { return native_get_pos_update_period(); } - + /** * Returns the minimum buffer size required for the successful creation of an AudioRecord * object. + * Note that this size doesn't guarantee a smooth recording under load, and higher values + * should be chosen according to the expected frequency at which the AudioRecord instance + * will be polled for new data. * @param sampleRateInHz the sample rate expressed in Hertz. * @param channelConfig describes the configuration of the audio channels. * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and @@ -432,7 +439,7 @@ public class AudioRecord * hardware, or an invalid parameter was passed, * or {@link #ERROR} if the implementation was unable to query the hardware for its * output properties, - * or the minimum buffer size expressed in of bytes. + * or the minimum buffer size expressed in bytes. */ static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { int channelCount = 0; @@ -516,7 +523,7 @@ public class AudioRecord /** * Reads audio data from the audio hardware for recording into a buffer. * @param audioData the array to which the recorded audio data is written. - * @param offsetInBytes index in audioData from which the data is written. + * @param offsetInBytes index in audioData from which the data is written expressed in bytes. * @param sizeInBytes the number of requested bytes. * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION} * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if @@ -540,9 +547,9 @@ public class AudioRecord /** * Reads audio data from the audio hardware for recording into a buffer. * @param audioData the array to which the recorded audio data is written. - * @param offsetInShorts index in audioData from which the data is written. + * @param offsetInShorts index in audioData from which the data is written expressed in shorts. * @param sizeInShorts the number of requested shorts. - * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION} + * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION} * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if * the parameters don't resolve to valid data and indexes. * The number of shorts will not exceed sizeInShorts. @@ -595,8 +602,15 @@ public class AudioRecord public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) { setRecordPositionUpdateListener(listener, null); } - + /** + * Sets the listener the AudioRecord notifies when a previously set marker is reached or + * for each periodic record head position update. + * Use this method to receive AudioRecord events in the Handler associated with another + * thread than the one in which you created the AudioTrack instance. + * @param listener + * @param handler the Handler that will receive the event notification messages. + */ public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler) { synchronized (mPositionListenerLock) { @@ -616,8 +630,8 @@ public class AudioRecord } } - - + + /** * Sets the marker position at which the listener is called, if set with * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or @@ -629,8 +643,8 @@ public class AudioRecord public int setNotificationMarkerPosition(int markerInFrames) { return native_set_marker_pos(markerInFrames); } - - + + /** * Sets the period at which the listener is called, if set with * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or @@ -648,7 +662,9 @@ public class AudioRecord //-------------------- /** * Interface definition for a callback to be invoked when an AudioRecord has - * reached a notification marker set by setNotificationMarkerPosition(). + * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)} + * or for periodic updates on the progress of the record head, as set by + * {@link AudioRecord#setPositionNotificationPeriod(int)}. */ public interface OnRecordPositionUpdateListener { /** @@ -663,10 +679,9 @@ public class AudioRecord */ void onPeriodicNotification(AudioRecord recorder); } - - - + + //--------------------------------------------------------- // Inner classes //-------------------- @@ -678,12 +693,12 @@ public class AudioRecord private class NativeEventHandler extends Handler { private final AudioRecord mAudioRecord; - + NativeEventHandler(AudioRecord recorder, Looper looper) { super(looper); mAudioRecord = recorder; } - + @Override public void handleMessage(Message msg) { OnRecordPositionUpdateListener listener = null; @@ -779,7 +794,3 @@ public class AudioRecord } - - - - diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 2e3e46014136e4242727421fc0ca83ac44dd7def..881de4d2a468f6176784dd66f973baa73da4a13f 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -100,6 +100,10 @@ public class AudioService extends IAudioService.Stub { private int[] mRoutes = new int[AudioSystem.NUM_MODES]; private Object mSettingsLock = new Object(); private boolean mMediaServerOk; + private boolean mSpeakerIsOn; + private boolean mBluetoothScoIsConnected; + private boolean mHeadsetIsConnected; + private boolean mBluetoothA2dpIsConnected; private SoundPool mSoundPool; private Object mSoundEffectsLock = new Object(); @@ -189,6 +193,10 @@ public class AudioService extends IAudioService.Stub { mMediaServerOk = true; AudioSystem.setErrorCallback(mAudioSystemCallback); loadSoundEffects(); + mSpeakerIsOn = false; + mBluetoothScoIsConnected = false; + mHeadsetIsConnected = false; + mBluetoothA2dpIsConnected = false; } private void createAudioSystemThread() { @@ -606,8 +614,9 @@ public class AudioService extends IAudioService.Stub { } synchronized (mSettingsLock) { if (mode != mMode) { - AudioSystem.setMode(mode); - mMode = mode; + if (AudioSystem.setMode(mode) == AudioSystem.AUDIO_STATUS_OK) { + mMode = mode; + } } int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); int index = mStreamStates[streamType].mIndex; @@ -623,18 +632,167 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#setRouting(int, int, int) */ public void setRouting(int mode, int routes, int mask) { + int incallMask = 0; + int ringtoneMask = 0; + int normalMask = 0; + if (!checkAudioSettingsPermission("setRouting()")) { return; } synchronized (mSettingsLock) { - if ((mRoutes[mode] & mask) != (routes & mask)) { - AudioSystem.setRouting(mode, routes, mask); - mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask); + // Temporary fix for issue #1713090 until audio routing is refactored in eclair release. + // mode AudioSystem.MODE_INVALID is used only by the following AudioManager methods: + // setWiredHeadsetOn(), setBluetoothA2dpOn(), setBluetoothScoOn() and setSpeakerphoneOn(). + // If applications are using AudioManager.setRouting() that is now deprecated, the routing + // command will be ignored. + if (mode == AudioSystem.MODE_INVALID) { + switch (mask) { + case AudioSystem.ROUTE_SPEAKER: + // handle setSpeakerphoneOn() + if (routes != 0 && !mSpeakerIsOn) { + mSpeakerIsOn = true; + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER; + incallMask = AudioSystem.ROUTE_ALL; + } else if (mSpeakerIsOn) { + mSpeakerIsOn = false; + if (mBluetoothScoIsConnected) { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO; + } else if (mHeadsetIsConnected) { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET; + } else { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE; + } + incallMask = AudioSystem.ROUTE_ALL; + } + break; + + case AudioSystem.ROUTE_BLUETOOTH_SCO: + // handle setBluetoothScoOn() + if (routes != 0 && !mBluetoothScoIsConnected) { + mBluetoothScoIsConnected = true; + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO; + mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_BLUETOOTH_SCO; + mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_BLUETOOTH_SCO; + incallMask = AudioSystem.ROUTE_ALL; + // A2DP has higher priority than SCO headset, so headset connect/disconnect events + // should not affect A2DP routing + ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + } else if (mBluetoothScoIsConnected) { + mBluetoothScoIsConnected = false; + if (mHeadsetIsConnected) { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET; + mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER); + mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_HEADSET; + } else { + if (mSpeakerIsOn) { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER; + } else { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE; + } + mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_SPEAKER; + mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_SPEAKER; + } + incallMask = AudioSystem.ROUTE_ALL; + // A2DP has higher priority than SCO headset, so headset connect/disconnect events + // should not affect A2DP routing + ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + } + break; + + case AudioSystem.ROUTE_HEADSET: + // handle setWiredHeadsetOn() + if (routes != 0 && !mHeadsetIsConnected) { + mHeadsetIsConnected = true; + // do not act upon headset connection if bluetooth SCO is connected to match phone app behavior + if (!mBluetoothScoIsConnected) { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET; + mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER); + mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_HEADSET; + incallMask = AudioSystem.ROUTE_ALL; + // A2DP has higher priority than wired headset, so headset connect/disconnect events + // should not affect A2DP routing + ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + } + } else if (mHeadsetIsConnected) { + mHeadsetIsConnected = false; + // do not act upon headset disconnection if bluetooth SCO is connected to match phone app behavior + if (!mBluetoothScoIsConnected) { + if (mSpeakerIsOn) { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER; + } else { + mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE; + } + mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_SPEAKER; + mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) | + AudioSystem.ROUTE_SPEAKER; + + incallMask = AudioSystem.ROUTE_ALL; + // A2DP has higher priority than wired headset, so headset connect/disconnect events + // should not affect A2DP routing + ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + } + } + break; + + case AudioSystem.ROUTE_BLUETOOTH_A2DP: + // handle setBluetoothA2dpOn() + if (routes != 0 && !mBluetoothA2dpIsConnected) { + mBluetoothA2dpIsConnected = true; + mRoutes[AudioSystem.MODE_RINGTONE] |= AudioSystem.ROUTE_BLUETOOTH_A2DP; + mRoutes[AudioSystem.MODE_NORMAL] |= AudioSystem.ROUTE_BLUETOOTH_A2DP; + // the audio flinger chooses A2DP as a higher priority, + // so there is no need to disable other routes. + ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP; + normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP; + } else if (mBluetoothA2dpIsConnected) { + mBluetoothA2dpIsConnected = false; + mRoutes[AudioSystem.MODE_RINGTONE] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + mRoutes[AudioSystem.MODE_NORMAL] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP; + // the audio flinger chooses A2DP as a higher priority, + // so there is no need to disable other routes. + ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP; + normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP; + } + break; + } + + // incallMask is != 0 means we must apply ne routing to MODE_IN_CALL mode + if (incallMask != 0) { + AudioSystem.setRouting(AudioSystem.MODE_IN_CALL, + mRoutes[AudioSystem.MODE_IN_CALL], + incallMask); + } + // ringtoneMask is != 0 means we must apply ne routing to MODE_RINGTONE mode + if (ringtoneMask != 0) { + AudioSystem.setRouting(AudioSystem.MODE_RINGTONE, + mRoutes[AudioSystem.MODE_RINGTONE], + ringtoneMask); + } + // normalMask is != 0 means we must apply ne routing to MODE_NORMAL mode + if (normalMask != 0) { + AudioSystem.setRouting(AudioSystem.MODE_NORMAL, + mRoutes[AudioSystem.MODE_NORMAL], + normalMask); + } + + int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); + int index = mStreamStates[streamType].mIndex; + syncRingerAndNotificationStreamVolume(streamType, index, true); + setStreamVolumeInt(streamType, index, true); } - int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); - int index = mStreamStates[streamType].mIndex; - syncRingerAndNotificationStreamVolume(streamType, index, true); - setStreamVolumeInt(streamType, index, true); } } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index d0fa7953dd210add1ab1c62b5a597927db95bf34..5917ab90e6c73bd97d6cdc649a9da32038fd5442 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -200,7 +200,7 @@ public class AudioSystem * param error error code: * - AUDIO_STATUS_OK * - AUDIO_STATUS_SERVER_DIED - * - UDIO_STATUS_ERROR + * - AUDIO_STATUS_ERROR */ void onError(int error); }; diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 4196ef398b65a8ce0881afe607b76de8ef80416b..3cd841de4145617585476e363eb376b0c1d024e2 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -32,22 +32,24 @@ import android.util.Log; * It allows to stream PCM audio buffers to the audio hardware for playback. This is * achieved by "pushing" the data to the AudioTrack object using one of the * {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods. - *

          An AudioTrack instance can operate under two modes: static of streaming.
          - * The Streaming mode consists in continuously writing data to the AudioTrack, using one - * of the write() methods. These are blocking and return when the data has been transferred - * from the Java layer to the native layer, and is queued for playback. The streaming mode + * + *

          An AudioTrack instance can operate under two modes: static or streaming.
          + * In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using + * one of the write() methods. These are blocking and return when the data has been transferred + * from the Java layer to the native layer and queued for playback. The streaming mode * is most useful when playing blocks of audio data that for instance are: *

            *
          • too big to fit in memory because of the duration of the sound to play,
          • *
          • too big to fit in memory because of the characteristics of the audio data * (high sampling rate, bits per sample ...)
          • - *
          • chosen, received or generated as the audio keeps playing.
          • + *
          • received or generated while previously queued audio is playing.
          • *
          * The static mode is to be chosen when dealing with short sounds that fit in memory and - * that need to be played with the smallest latency possible. Static mode AudioTrack instances can - * play the sound without the need to transfer the audio data from Java to the audio hardware + * that need to be played with the smallest latency possible. AudioTrack instances in static mode + * can play the sound without the need to transfer the audio data from Java to native layer * each time the sound is to be played. The static mode will therefore be preferred for UI and * game sounds that are played often, and with the smallest overhead possible. + * *

          Upon creation, an AudioTrack object initializes its associated audio buffer. * The size of this buffer, specified during the construction, determines how long an AudioTrack * can play before running out of data.
          @@ -66,11 +68,11 @@ public class AudioTrack /** Maximum value for a channel volume */ private static final float VOLUME_MAX = 1.0f; - /** state of an AudioTrack this is stopped */ + /** indicates AudioTrack state is stopped */ public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED - /** state of an AudioTrack this is paused */ + /** indicates AudioTrack state is paused */ public static final int PLAYSTATE_PAUSED = 2; // matches SL_PLAYSTATE_PAUSED - /** state of an AudioTrack this is playing */ + /** indicates AudioTrack state is playing */ public static final int PLAYSTATE_PLAYING = 3; // matches SL_PLAYSTATE_PLAYING /** @@ -85,7 +87,7 @@ public class AudioTrack public static final int MODE_STREAM = 1; /** - * State of an AudioTrack that was not successfully initialized upon creation + * State of an AudioTrack that was not successfully initialized upon creation. */ public static final int STATE_UNINITIALIZED = 0; /** @@ -126,11 +128,11 @@ public class AudioTrack // Events: // to keep in sync with frameworks/base/include/media/AudioTrack.h /** - * Event id for when the playback head has reached a previously set marker. + * Event id denotes when playback head has reached a previously set marker. */ private static final int NATIVE_EVENT_MARKER = 3; /** - * Event id for when the previously set update period has passed during playback. + * Event id denotes when previously set update period has elapsed during playback. */ private static final int NATIVE_EVENT_NEW_POS = 4; @@ -141,11 +143,11 @@ public class AudioTrack // Member variables //-------------------- /** - * Indicates the state of the AudioTrack instance + * Indicates the state of the AudioTrack instance. */ private int mState = STATE_UNINITIALIZED; /** - * Indicates the play state of the AudioTrack instance + * Indicates the play state of the AudioTrack instance. */ private int mPlayState = PLAYSTATE_STOPPED; /** @@ -159,7 +161,7 @@ public class AudioTrack */ private OnPlaybackPositionUpdateListener mPositionListener = null; /** - * Lock to protect event listener updates against event notifications + * Lock to protect event listener updates against event notifications. */ private final Object mPositionListenerLock = new Object(); /** @@ -167,11 +169,11 @@ public class AudioTrack */ private int mNativeBufferSizeInBytes = 0; /** - * Handler for marker events coming from the native code + * Handler for marker events coming from the native code. */ private NativeEventHandlerDelegate mEventHandlerDelegate = null; /** - * Looper associated with the thread that creates the AudioTrack instance + * Looper associated with the thread that creates the AudioTrack instance. */ private Looper mInitializationLooper = null; /** @@ -179,7 +181,7 @@ public class AudioTrack */ private int mSampleRate = 22050; /** - * The number of input audio channels (1 is mono, 2 is stereo) + * The number of input audio channels (1 is mono, 2 is stereo). */ private int mChannelCount = 1; /** @@ -194,7 +196,7 @@ public class AudioTrack */ private int mDataLoadMode = MODE_STREAM; /** - * The current audio channel configuration + * The current audio channel configuration. */ private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; /** @@ -209,7 +211,7 @@ public class AudioTrack // Used exclusively by native code //-------------------- /** - * Accessed by native methods: provides access to C++ AudioTrack object + * Accessed by native methods: provides access to C++ AudioTrack object. */ @SuppressWarnings("unused") private int mNativeTrackInJavaObj; @@ -227,17 +229,14 @@ public class AudioTrack /** * Class constructor. * @param streamType the type of the audio stream. See - * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and * {@link AudioManager#STREAM_ALARM} * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but * not limited to) 44100, 22050 and 11025. * @param channelConfig describes the configuration of the audio channels. - * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} - * @param audioFormat the format in which the audio data is represented. * See {@link AudioFormat#ENCODING_PCM_16BIT} and * {@link AudioFormat#ENCODING_PCM_8BIT} @@ -245,6 +244,9 @@ public class AudioTrack * from for playback. If using the AudioTrack in streaming mode, you can write data into * this buffer in smaller chunks than this size. If using the AudioTrack in static mode, * this is the maximum size of the sound that will be played for this instance. + * See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size + * for the successful creation of an AudioTrack instance in streaming mode. Using values + * smaller than getMinBufferSize() will result in an initialization failure. * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM} * @throws java.lang.IllegalArgumentException */ @@ -423,8 +425,8 @@ public class AudioTrack } /** - * Returns the current playback rate in Hz. Note that this rate may differ from one set using - * {@link #setPlaybackRate(int)} as the value effectively set is implementation-dependent. + * Returns the current playback rate in Hz. Note that this rate may differ from the one set + * with {@link #setPlaybackRate(int)} as the value effectively used is implementation-dependent. */ public int getPlaybackRate() { return native_get_playback_rate(); @@ -470,6 +472,9 @@ public class AudioTrack * AudioTrack instance has been created to check if it was initialized * properly. This ensures that the appropriate hardware resources have been * acquired. + * @see #STATE_INITIALIZED + * @see #STATE_NO_STATIC_DATA + * @see #STATE_UNINITIALIZED */ public int getState() { return mState; @@ -486,28 +491,28 @@ public class AudioTrack } /** - * Returns the native frame count used by the hardware + * Returns the native frame count used by the hardware. */ protected int getNativeFrameCount() { return native_get_native_frame_count(); } /** - * @return marker position in frames + * Returns marker position expressed in frames. */ public int getNotificationMarkerPosition() { return native_get_marker_pos(); } /** - * @return update period in frames + * Returns the notification update period expressed in frames. */ public int getPositionNotificationPeriod() { return native_get_pos_update_period(); } /** - * @return playback head position in frames + * Returns the playback head position expressed in frames */ public int getPlaybackHeadPosition() { return native_get_position(); @@ -522,7 +527,9 @@ public class AudioTrack /** * Returns the minimum buffer size required for the successful creation of an AudioTrack - * object to be created in the {@link #MODE_STREAM} mode. + * object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't + * guarantee a smooth playback under load, and higher values should be chosen according to + * the expected frequency at which the buffer will be refilled with additional data to play. * @param sampleRateInHz the sample rate expressed in Hertz. * @param channelConfig describes the configuration of the audio channels. * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and @@ -533,7 +540,7 @@ public class AudioTrack * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed, * or {@link #ERROR} if the implementation was unable to query the hardware for its output * properties, - * or the minimum buffer size expressed in number of bytes. + * or the minimum buffer size expressed in bytes. */ static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { int channelCount = 0; @@ -577,13 +584,22 @@ public class AudioTrack /** * Sets the listener the AudioTrack notifies when a previously set marker is reached or * for each periodic playback head position update. + * Notifications will be received in the same thread as the one in which the AudioTrack + * instance was created. * @param listener */ public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener) { setPlaybackPositionUpdateListener(listener, null); } - + /** + * Sets the listener the AudioTrack notifies when a previously set marker is reached or + * for each periodic playback head position update. + * Use this method to receive AudioTrack events in the Handler associated with another + * thread than the one in which you created the AudioTrack instance. + * @param listener + * @param handler the Handler that will receive the event notification messages. + */ public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener, Handler handler) { synchronized (mPositionListenerLock) { @@ -636,13 +652,17 @@ public class AudioTrack * the audio data will be consumed and played back, not the original sampling rate of the * content. Setting it to half the sample rate of the content will cause the playback to * last twice as long, but will also result result in a negative pitch shift. - * The current implementation supports a maximum sample rate of twice the hardware output - * sample rate (see {@link #getNativeOutputSampleRate(int)}). Use {@link #getSampleRate()} to - * check the rate actually used in hardware after potential clamping. - * @param sampleRateInHz + * The current implementation supports a maximum sample rate of 64kHz. + * Use {@link #getSampleRate()} to check the rate actually used in hardware after + * potential clamping. + * @param sampleRateInHz the sample rate expressed in Hz * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, * {@link #ERROR_INVALID_OPERATION} */ + // FIXME: the implementation should support twice the hardware output sample rate + // (see {@link #getNativeOutputSampleRate(int)}), but currently + // due to the representation of the sample rate in the native layer, the sample rate + // is limited to 65535Hz public int setPlaybackRate(int sampleRateInHz) { if (mState != STATE_INITIALIZED) { return ERROR_INVALID_OPERATION; @@ -656,7 +676,7 @@ public class AudioTrack /** - * + * Sets the position of the notification marker. * @param markerInFrames marker in frames * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, * {@link #ERROR_INVALID_OPERATION} @@ -670,7 +690,8 @@ public class AudioTrack /** - * @param periodInFrames update period in frames + * Sets the period for the periodic notification event. + * @param periodInFrames update period expressed in frames * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} */ public int setPositionNotificationPeriod(int periodInFrames) { @@ -683,7 +704,7 @@ public class AudioTrack /** * Sets the playback head position. The track must be stopped for the position to be changed. - * @param positionInFrames playback head position in frames + * @param positionInFrames playback head position expressed in frames * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, * {@link #ERROR_INVALID_OPERATION} */ @@ -699,8 +720,8 @@ public class AudioTrack /** * Sets the loop points and the loop count. The loop can be infinite. - * @param startInFrames loop start marker in frames - * @param endInFrames loop end marker in frames + * @param startInFrames loop start marker expressed in frames + * @param endInFrames loop end marker expressed in frames * @param loopCount the number of times the loop is looped. * A value of -1 means infinite looping. * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, @@ -797,7 +818,8 @@ public class AudioTrack /** * Writes the audio data to the audio hardware for playback. * @param audioData the array that holds the data to play. - * @param offsetInBytes the offset in audioData where the data to play starts. + * @param offsetInBytes the offset expressed in bytes in audioData where the data to play + * starts. * @param sizeInBytes the number of bytes to read in audioData after the offset. * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION} * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if @@ -827,7 +849,8 @@ public class AudioTrack /** * Writes the audio data to the audio hardware for playback. * @param audioData the array that holds the data to play. - * @param offsetInShorts the offset in audioData where the data to play starts. + * @param offsetInShorts the offset expressed in shorts in audioData where the data to play + * starts. * @param sizeInShorts the number of bytes to read in audioData after the offset. * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION} * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java index c9efac5cdb19428477300e0f18ed9db0f1aac907..4fb0ead7ff59b15c57086f1f4fe4accb15ca5ea7 100644 --- a/media/java/android/media/JetPlayer.java +++ b/media/java/android/media/JetPlayer.java @@ -30,8 +30,29 @@ import android.util.Log; /** * JetPlayer provides access to JET content playback and control. - *

          - * Use JetPlayer.getJetPlayer() to get an instance of this class. + * + *

          Please refer to the JET Creator User Manual for a presentation of the JET interactive + * music concept and how to use the JetCreator tool to create content to be player by JetPlayer. + * + *

          Use of the JetPlayer class is based around the playback of a number of JET segments + * sequentially added to a playback FIFO queue. The rendering of the MIDI content stored in each + * segment can be dynamically affected by two mechanisms: + *

            + *
          • tracks in a segment can be muted or unmuted at any moment, individually or through + * a mask (to change the mute state of multiple tracks at once)
          • + *
          • parts of tracks in a segment can be played at predefined points in the segment, in order + * to maintain synchronization with the other tracks in the segment. This is achieved through + * the notion of "clips", which can be triggered at any time, but that will play only at the + * right time, as authored in the corresponding JET file.
          • + *
          + * As a result of the rendering and playback of the JET segments, the user of the JetPlayer instance + * can receive notifications from the JET engine relative to: + *
            + *
          • the playback state,
          • + *
          • the number of segments left to play in the queue,
          • + *
          • application controller events (CC80-83) to mark points in the MIDI segments.
          • + *
          + * Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class. * */ public class JetPlayer @@ -40,7 +61,7 @@ public class JetPlayer // Constants //------------------------ /** - * The maximum number of simultaneous tracks. Use __link #getMaxTracks()} to + * The maximum number of simultaneous tracks. Use {@link #getMaxTracks()} to * access this value. */ private static int MAXTRACKS = 32; @@ -107,6 +128,10 @@ public class JetPlayer //-------------------------------------------- // Constructor, finalize //------------------------ + /** + * Factory method for the JetPlayer class. + * @return the singleton JetPlayer instance + */ public static JetPlayer getJetPlayer() { if (singletonRef == null) { singletonRef = new JetPlayer(); @@ -114,7 +139,9 @@ public class JetPlayer return singletonRef; } - + /** + * Cloning a JetPlayer instance is not supported. Calling clone() will generate an exception. + */ public Object clone() throws CloneNotSupportedException { // JetPlayer is a singleton class, // so you can't clone a JetPlayer instance @@ -149,6 +176,11 @@ public class JetPlayer } + /** + * Stops the current JET playback, and releases all associated native resources. + * The object can no longer be used and the reference should be set to null + * after a call to release(). + */ public void release() { native_release(); } @@ -158,7 +190,7 @@ public class JetPlayer // Getters //------------------------ /** - * Returns the maximum number of simultaneous MIDI tracks supported by the Jet player + * Returns the maximum number of simultaneous MIDI tracks supported by JetPlayer */ public static int getMaxTracks() { return JetPlayer.MAXTRACKS; @@ -168,11 +200,21 @@ public class JetPlayer //-------------------------------------------- // Jet functionality //------------------------ + /** + * Loads a .jet file from a given path. + * @param path the path to the .jet file, for instance "/sdcard/mygame/music.jet". + * @return true if loading the .jet file was successful, false if loading failed. + */ public boolean loadJetFile(String path) { return native_loadJetFromFile(path); } + /** + * Loads a .jet file from an asset file descriptor. + * @param afd the asset file descriptor. + * @return true if loading the .jet file was successful, false if loading failed. + */ public boolean loadJetFile(AssetFileDescriptor afd) { long len = afd.getLength(); if (len < 0) { @@ -182,22 +224,54 @@ public class JetPlayer afd.getFileDescriptor(), afd.getStartOffset(), len); } - + /** + * Closes the resource containing the JET content. + * @return true if successfully closed, false otherwise. + */ public boolean closeJetFile() { return native_closeJetFile(); } + /** + * Starts playing the JET segment queue. + * @return true if rendering and playback is successfully started, false otherwise. + */ public boolean play() { return native_playJet(); } + /** + * Pauses the playback of the JET segment queue. + * @return true if rendering and playback is successfully paused, false otherwise. + */ public boolean pause() { return native_pauseJet(); } + /** + * Queues the specified segment in the JET queue. + * @param segmentNum the identifier of the segment. + * @param libNum the index of the sound bank associated with the segment. Use -1 to indicate + * that no sound bank (DLS file) is associated with this segment, in which case JET will use + * the General MIDI library. + * @param repeatCount the number of times the segment will be repeated. 0 means the segment will + * only play once. -1 means the segment will repeat indefinitely. + * @param transpose the amount of pitch transposition. Set to 0 for normal playback. + * Range is -12 to +12. + * @param muteFlags a bitmask to specify which MIDI tracks will be muted during playback. Bit 0 + * affects track 0, bit 1 affects track 1 etc. + * @param userID a value specified by the application that uniquely identifies the segment. + * this value is received in the + * {@link OnJetEventListener#onJetUserIdUpdate(JetPlayer, int, int)} event listener method. + * Normally, the application will keep a byte value that is incremented each time a new + * segment is queued up. This can be used to look up any special characteristics of that + * track including trigger clips and mute flags. + * @return true if the segment was successfully queued, false if the queue is full or if the + * parameters are invalid. + */ public boolean queueJetSegment(int segmentNum, int libNum, int repeatCount, int transpose, int muteFlags, byte userID) { return native_queueJetSegment(segmentNum, libNum, repeatCount, @@ -205,6 +279,28 @@ public class JetPlayer } + /** + * Queues the specified segment in the JET queue. + * @param segmentNum the identifier of the segment. + * @param libNum the index of the soundbank associated with the segment. Use -1 to indicate that + * no sound bank (DLS file) is associated with this segment, in which case JET will use + * the General MIDI library. + * @param repeatCount the number of times the segment will be repeated. 0 means the segment will + * only play once. -1 means the segment will repeat indefinitely. + * @param transpose the amount of pitch transposition. Set to 0 for normal playback. + * Range is -12 to +12. + * @param muteArray an array of booleans to specify which MIDI tracks will be muted during + * playback. The value at index 0 affects track 0, value at index 1 affects track 1 etc. + * The length of the array must be {@link #getMaxTracks()} for the call to succeed. + * @param userID a value specified by the application that uniquely identifies the segment. + * this value is received in the + * {@link OnJetEventListener#onJetUserIdUpdate(JetPlayer, int, int)} event listener method. + * Normally, the application will keep a byte value that is incremented each time a new + * segment is queued up. This can be used to look up any special characteristics of that + * track including trigger clips and mute flags. + * @return true if the segment was successfully queued, false if the queue is full or if the + * parameters are invalid. + */ public boolean queueJetSegmentMuteArray(int segmentNum, int libNum, int repeatCount, int transpose, boolean[] muteArray, byte userID) { if (muteArray.length != JetPlayer.getMaxTracks()) { @@ -215,11 +311,32 @@ public class JetPlayer } + /** + * Modifies the mute flags. + * @param muteFlags a bitmask to specify which MIDI tracks are muted. Bit 0 affects track 0, + * bit 1 affects track 1 etc. + * @param sync if false, the new mute flags will be applied as soon as possible by the JET + * render and playback engine. If true, the mute flags will be updated at the start of the + * next segment. If the segment is repeated, the flags will take effect the next time + * segment is repeated. + * @return true if the mute flags were successfully updated, false otherwise. + */ public boolean setMuteFlags(int muteFlags, boolean sync) { return native_setMuteFlags(muteFlags, sync); } + /** + * Modifies the mute flags for the current active segment. + * @param muteArray an array of booleans to specify which MIDI tracks are muted. The value at + * index 0 affects track 0, value at index 1 affects track 1 etc. + * The length of the array must be {@link #getMaxTracks()} for the call to succeed. + * @param sync if false, the new mute flags will be applied as soon as possible by the JET + * render and playback engine. If true, the mute flags will be updated at the start of the + * next segment. If the segment is repeated, the flags will take effect the next time + * segment is repeated. + * @return true if the mute flags were successfully updated, false otherwise. + */ public boolean setMuteArray(boolean[] muteArray, boolean sync) { if(muteArray.length != JetPlayer.getMaxTracks()) return false; @@ -227,16 +344,41 @@ public class JetPlayer } + /** + * Mutes or unmutes a single track. + * @param trackId the index of the track to mute. + * @param muteFlag set to true to mute, false to unmute. + * @param sync if false, the new mute flags will be applied as soon as possible by the JET + * render and playback engine. If true, the mute flag will be updated at the start of the + * next segment. If the segment is repeated, the flag will take effect the next time + * segment is repeated. + * @return true if the mute flag was successfully updated, false otherwise. + */ public boolean setMuteFlag(int trackId, boolean muteFlag, boolean sync) { return native_setMuteFlag(trackId, muteFlag, sync); } + /** + * Schedules the playback of a clip. + * This will automatically update the mute flags in sync with the JET Clip Marker (controller + * 103). The parameter clipID must be in the range of 0-63. After the call to triggerClip, when + * JET next encounters a controller event 103 with bits 0-5 of the value equal to clipID and + * bit 6 set to 1, it will automatically unmute the track containing the controller event. + * When JET encounters the complementary controller event 103 with bits 0-5 of the value equal + * to clipID and bit 6 set to 0, it will mute the track again. + * @param clipId the identifier of the clip to trigger. + * @return true if the clip was successfully triggered, false otherwise. + */ public boolean triggerClip(int clipId) { return native_triggerClip(clipId); } + /** + * Empties the segment queue, and clears all clips that are scheduled for playback. + * @return true if the queue was successfully cleared, false otherwise. + */ public boolean clearQueue() { return native_clearQueue(); } @@ -302,10 +444,25 @@ public class JetPlayer //-------------------------------------------- // Jet event listener //------------------------ + /** + * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and + * playback engine. + * Notifications will be received in the same thread as the one in which the JetPlayer + * instance was created. + * @param listener + */ public void setEventListener(OnJetEventListener listener) { setEventListener(listener, null); } + /** + * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and + * playback engine. + * Use this method to receive JET events in the Handler associated with another + * thread than the one in which you created the JetPlayer instance. + * @param listener + * @param handler the Handler that will receive the event notification messages. + */ public void setEventListener(OnJetEventListener listener, Handler handler) { synchronized(mEventListenerLock) { @@ -343,7 +500,7 @@ public class JetPlayer void onJetEvent(JetPlayer player, short segment, byte track, byte channel, byte controller, byte value); /** - * Callback for when JET's currently playing segment userID is updated. + * Callback for when JET's currently playing segment's userID is updated. * * @param player the JET player the status update is coming from * @param userId the ID of the currently playing segment @@ -363,7 +520,7 @@ public class JetPlayer * Callback for when JET pause state is updated. * * @param player the JET player the status update is coming from - * @param paused indicates whether JET is paused or not + * @param paused indicates whether JET is paused (1) or not (0) */ void onJetPauseUpdate(JetPlayer player, int paused); } diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index f05842d6ce02bac3547c05cc025cb60bbfc6c1d1..8be11df0fd2732ef474a818c841e85e2f1ad907a 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -31,7 +31,7 @@ import java.util.Iterator; */ public class MediaFile { // comma separated list of all file extensions supported by the media scanner - public static String sFileExtensions; + public final static String sFileExtensions; // Audio file types public static final int FILE_TYPE_MP3 = 1; @@ -93,7 +93,7 @@ public class MediaFile { = new HashMap(); static void addFileType(String extension, int fileType, String mimeType) { sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType)); - sMimeTypeMap.put(mimeType, new Integer(fileType)); + sMimeTypeMap.put(mimeType, Integer.valueOf(fileType)); } static { addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg"); diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index fc8476d4ae83f0b67d702e346119ca76c8e24eb8..ae3e181041d6f0139d82f3eaeb6127652bf754e9 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -453,11 +453,12 @@ public class MediaScanner FileCacheEntry entry = beginFile(path, mimeType, lastModified, fileSize); // rescan for metadata if file was modified since last scan if (entry != null && (entry.mLastModifiedChanged || scanAlways)) { - boolean ringtones = (path.indexOf(RINGTONES_DIR) > 0); - boolean notifications = (path.indexOf(NOTIFICATIONS_DIR) > 0); - boolean alarms = (path.indexOf(ALARMS_DIR) > 0); - boolean podcasts = (path.indexOf(PODCAST_DIR) > 0); - boolean music = (path.indexOf(MUSIC_DIR) > 0) || + String lowpath = path.toLowerCase(); + boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0); + boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0); + boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0); + boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0); + boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) || (!ringtones && !notifications && !alarms && !podcasts); if (mFileType == MediaFile.FILE_TYPE_MP3 || diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index ab3274b1aa66fdf159a76b66d9a352c0a4f776da..3803d9dfccb7b5460f5e04a4dfba4b001230760a 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -46,6 +46,19 @@ import java.io.IOException; * number of streams helps to cap CPU loading and reducing the likelihood that * audio mixing will impact visuals or UI performance.

          * + *

          Sounds can be looped by setting a non-zero loop value. A value of -1 + * causes the sound to loop forever. In this case, the application must + * explicitly call the stop() function to stop the sound. Any other non-zero + * value will cause the sound to repeat the specified number of times, e.g. + * a value of 3 causes the sound to play a total of 4 times.

          + * + *

          The playback rate can also be changed. A playback rate of 1.0 causes + * the sound to play at its original frequency (resampled, if necessary, + * to the hardware output frequency). A playback rate of 2.0 causes the + * sound to play at twice its original frequency, and a playback rate of + * 0.5 causes it to play at half its original frequency. The playback + * rate range is 0.5 to 2.0.

          + * *

          Priority runs low to high, i.e. higher numbers are higher priority. * Priority is used when a call to play() would cause the number of active * streams to exceed the value established by the maxStreams parameter when @@ -72,6 +85,13 @@ import java.io.IOException; * adjusting the playback rate in real-time for doppler or synthesis * effects.

          * + *

          Note that since streams can be stopped due to resource constraints, the + * streamID is a reference to a particular instance of a stream. If the stream + * is stopped to allow a higher priority stream to play, the stream is no + * longer be valid. However, the application is allowed to call methods on + * the streamID without error. This may help simplify program logic since + * the application need not concern itself with the stream lifecycle.

          + * *

          In our example, when the player has completed the level, the game * logic should call SoundPool.release() to release all the native resources * in use and then set the SoundPool reference to null. If the player starts @@ -104,10 +124,11 @@ public class SoundPool } /** - * Load the sound from the specified path - * + * Load the sound from the specified path. + * * @param path the path to the audio file - * @param priority the priority of the sound. Currently has no effect. + * @param priority the priority of the sound. Currently has no effect. Use + * a value of 1 for future compatibility. * @return a sound ID. This value can be used to play or unload the sound. */ public int load(String path, int priority) @@ -128,22 +149,25 @@ public class SoundPool fd.close(); } } - } catch (java.io.IOException e) {} + } catch (java.io.IOException e) { + Log.d(TAG, "error loading " + path); + } return id; } /** - * Load the sound from the specified APK resource + * Load the sound from the specified APK resource. * - *

          Note that the extension is dropped. For example, if you want to load + * Note that the extension is dropped. For example, if you want to load * a sound from the raw resource file "explosion.mp3", you would specify * "R.raw.explosion" as the resource ID. Note that this means you cannot * have both an "explosion.wav" and an "explosion.mp3" in the res/raw - * directory.

          + * directory. * * @param context the application context * @param resId the resource ID - * @param priority the priority of the sound. Currently has no effect. + * @param priority the priority of the sound. Currently has no effect. Use + * a value of 1 for future compatibility. * @return a sound ID. This value can be used to play or unload the sound. */ public int load(Context context, int resId, int priority) { @@ -162,10 +186,11 @@ public class SoundPool } /** - * Load the sound from an asset file descriptor + * Load the sound from an asset file descriptor. * * @param afd an asset file descriptor - * @param priority the priority of the sound. Currently has no effect. + * @param priority the priority of the sound. Currently has no effect. Use + * a value of 1 for future compatibility. * @return a sound ID. This value can be used to play or unload the sound. */ public int load(AssetFileDescriptor afd, int priority) { @@ -181,16 +206,17 @@ public class SoundPool } /** - * Load the sound from a FileDescriptor + * Load the sound from a FileDescriptor. * - *

          This version is useful if you store multiple sounds in a single + * This version is useful if you store multiple sounds in a single * binary. The offset specifies the offset from the start of the file - * and the length specifies the length of the sound within the file.

          + * and the length specifies the length of the sound within the file. * * @param fd a FileDescriptor object * @param offset offset to the start of the sound * @param length length of the sound - * @param priority the priority of the sound. Currently has no effect. + * @param priority the priority of the sound. Currently has no effect. Use + * a value of 1 for future compatibility. * @return a sound ID. This value can be used to play or unload the sound. */ public int load(FileDescriptor fd, long offset, long length, int priority) { @@ -202,11 +228,11 @@ public class SoundPool private native final int _load(FileDescriptor fd, long offset, long length, int priority); /** - * Unload a sound from a sound ID + * Unload a sound from a sound ID. * - *

          Unloads the sound specified by the soundID. This is the value + * Unloads the sound specified by the soundID. This is the value * returned by the load() function. Returns true if the sound is - * successfully unloaded, false if the sound was already unloaded.

          + * successfully unloaded, false if the sound was already unloaded. * * @param soundID a soundID returned by the load() function * @return true if just unloaded, false if previously unloaded @@ -214,66 +240,77 @@ public class SoundPool public native final boolean unload(int soundID); /** - * Play a sound from a sound ID + * Play a sound from a sound ID. * - *

          Play the sound specified by the soundID. This is the value + * Play the sound specified by the soundID. This is the value * returned by the load() function. Returns a non-zero streamID * if successful, zero if it fails. The streamID can be used to * further control playback. Note that calling play() may cause * another sound to stop playing if the maximum number of active - * streams is exceeded.

          + * streams is exceeded. A loop value of -1 means loop forever, + * a value of 0 means don't loop, other values indicate the + * number of repeats, e.g. a value of 1 plays the audio twice. + * The playback rate allows the application to vary the playback + * rate (pitch) of the sound. A value of 1.0 means play back at + * the original frequency. A value of 2.0 means play back twice + * as fast, and a value of 0.5 means playback at half speed. * * @param soundID a soundID returned by the load() function + * @param leftVolume left volume value (range = 0.0 to 1.0) + * @param rightVolume right volume value (range = 0.0 to 1.0) + * @param priority stream priority (0 = lowest priority) + * @param loop loop mode (0 = no loop, -1 = loop forever) + * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0) * @return non-zero streamID if successful, zero if failed */ public native final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate); /** - * Pause a playback stream + * Pause a playback stream. * - *

          Pause the stream specified by the streamID. This is the + * Pause the stream specified by the streamID. This is the * value returned by the play() function. If the stream is * playing, it will be paused. If the stream is not playing * (e.g. is stopped or was previously paused), calling this - * function will have no effect.

          + * function will have no effect. * * @param streamID a streamID returned by the play() function */ public native final void pause(int streamID); /** - * Resume a playback stream + * Resume a playback stream. * - *

          Resume the stream specified by the streamID. This + * Resume the stream specified by the streamID. This * is the value returned by the play() function. If the stream * is paused, this will resume playback. If the stream was not - * previously paused, calling this function will have no effect.

          + * previously paused, calling this function will have no effect. * * @param streamID a streamID returned by the play() function */ public native final void resume(int streamID); /** - * Stop a playback stream + * Stop a playback stream. * - *

          Stop the stream specified by the streamID. This + * Stop the stream specified by the streamID. This * is the value returned by the play() function. If the stream * is playing, it will be stopped. It also releases any native * resources associated with this stream. If the stream is not - * playing, it will have no effect.

          + * playing, it will have no effect. * * @param streamID a streamID returned by the play() function */ public native final void stop(int streamID); /** - * Set stream volume + * Set stream volume. * - *

          Sets the volume on the stream specified by the streamID. + * Sets the volume on the stream specified by the streamID. * This is the value returned by the play() function. The * value must be in the range of 0.0 to 1.0. If the stream does - * not exist, it will have no effect.

          + * not exist, it will have no effect. * * @param streamID a streamID returned by the play() function * @param leftVolume left volume value (range = 0.0 to 1.0) @@ -283,29 +320,51 @@ public class SoundPool float leftVolume, float rightVolume); /** - * Change stream priority + * Change stream priority. * - *

          Change the priority of the stream specified by the streamID. + * Change the priority of the stream specified by the streamID. * This is the value returned by the play() function. Affects the - * order in which streams are re-used to play new sounds. + * order in which streams are re-used to play new sounds. If the + * stream does not exist, it will have no effect. * * @param streamID a streamID returned by the play() function */ public native final void setPriority(int streamID, int priority); /** - * Change stream priority + * Set loop mode. * - *

          Change the priority of the stream specified by the streamID. - * This is the value returned by the play() function. Affects the - * order in which streams are re-used to play new sounds. + * Change the loop mode. A loop value of -1 means loop forever, + * a value of 0 means don't loop, other values indicate the + * number of repeats, e.g. a value of 1 plays the audio twice. + * If the stream does not exist, it will have no effect. * * @param streamID a streamID returned by the play() function + * @param loop loop mode (0 = no loop, -1 = loop forever) */ public native final void setLoop(int streamID, int loop); + /** + * Change playback rate. + * + * The playback rate allows the application to vary the playback + * rate (pitch) of the sound. A value of 1.0 means playback at + * the original frequency. A value of 2.0 means playback twice + * as fast, and a value of 0.5 means playback at half speed. + * If the stream does not exist, it will have no effect. + * + * @param streamID a streamID returned by the play() function + * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0) + */ public native final void setRate(int streamID, float rate); + /** + * Release the SoundPool resources. + * + * Release all memory and native resources used by the SoundPool + * object. The SoundPool can no longer be used and the reference + * should be set to null. + */ public native final void release(); private native final void native_setup(Object mediaplayer_this, diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java index 0901fbfced07649e7eba917fc7e86f8277d57a8f..4b53756db118a5cb7d8f42737ece3523b529bf55 100644 --- a/media/java/android/media/ToneGenerator.java +++ b/media/java/android/media/ToneGenerator.java @@ -130,25 +130,35 @@ public class ToneGenerator */ public static final int TONE_DTMF_D = 15; /** - * Call supervisory tone, Dial tone: 425Hz, continuous - * + * Call supervisory tone, Dial tone: + * CEPT: 425Hz, continuous + * ANSI (IS-95): 350Hz+440Hz, continuous + * JAPAN: 400Hz, continuous + * * @see #ToneGenerator(int, int) */ public static final int TONE_SUP_DIAL = 16; /** - * Call supervisory tone, Busy: 425Hz, 500ms ON, 500ms OFF... - * + * Call supervisory tone, Busy: + * CEPT: 425Hz, 500ms ON, 500ms OFF... + * ANSI (IS-95): 480Hz+620Hz, 500ms ON, 500ms OFF... + * JAPAN: 400Hz, 500ms ON, 500ms OFF... + * * @see #ToneGenerator(int, int) */ public static final int TONE_SUP_BUSY = 17; /** - * Call supervisory tone, Congestion: 425Hz, 200ms ON, 200ms OFF... + * Call supervisory tone, Congestion: + * CEPT, JAPAN: 425Hz, 200ms ON, 200ms OFF... + * ANSI (IS-95): 480Hz+620Hz, 250ms ON, 250ms OFF... * * @see #ToneGenerator(int, int) */ public static final int TONE_SUP_CONGESTION = 18; /** - * Call supervisory tone, Radio path acknowlegment : 425Hz, 200ms ON + * Call supervisory tone, Radio path acknowlegment : + * CEPT, ANSI: 425Hz, 200ms ON + * JAPAN: 400Hz, 1s ON, 2s OFF... * * @see #ToneGenerator(int, int) */ @@ -166,13 +176,17 @@ public class ToneGenerator */ public static final int TONE_SUP_ERROR = 21; /** - * Call supervisory tone, Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF... + * Call supervisory tone, Call Waiting: + * CEPT, JAPAN: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF... + * ANSI (IS-95): 440 Hz, 300 ms ON, 9.7 s OFF, (100 ms ON, 100 ms OFF, 100 ms ON, 9.7s OFF ...) * * @see #ToneGenerator(int, int) */ public static final int TONE_SUP_CALL_WAITING = 22; /** - * Call supervisory tone, Ring Tone: 425Hz, 1s ON, 4s OFF... + * Call supervisory tone, Ring Tone: + * CEPT, JAPAN: 425Hz, 1s ON, 4s OFF... + * ANSI (IS-95): 440Hz + 480Hz, 2s ON, 4s OFF... * * @see #ToneGenerator(int, int) */ @@ -207,6 +221,37 @@ public class ToneGenerator * @see #ToneGenerator(int, int) */ public static final int TONE_PROP_BEEP2 = 28; + /** + * Call supervisory tone (IS-95), intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_INTERCEPT = 29; + /** + * Call supervisory tone (IS-95), abbreviated intercept: intercept tone limited to 4 seconds + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_INTERCEPT_ABBREV = 30; + /** + * Call supervisory tone (IS-95), abbreviated congestion: congestion tone limited to 4 seconds + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_CONGESTION_ABBREV = 31; + /** + * Call supervisory tone (IS-95), confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_CONFIRM = 32; + /** + * Call supervisory tone (IS-95), pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off). + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_PIP = 33; + /** Maximum volume, for use with {@link #ToneGenerator(int,int)} */ public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME; @@ -258,6 +303,11 @@ public class ToneGenerator *

        • {@link #TONE_PROP_NACK} *
        • {@link #TONE_PROP_PROMPT} *
        • {@link #TONE_PROP_BEEP2} + *
        • {@link #TONE_SUP_INTERCEPT} + *
        • {@link #TONE_SUP_INTERCEPT_ABBREV} + *
        • {@link #TONE_SUP_CONGESTION_ABBREV} + *
        • {@link #TONE_SUP_CONFIRM} + *
        • {@link #TONE_SUP_PIP} *
        * @see #ToneGenerator(int, int) */ diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 3620494ddde6afcf1e5bcdd95a552c0a44003b1f..8ee0cbdeb1e27bb7608f5f978c1531d88c5efe3a 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -3,31 +3,32 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - android_media_MediaPlayer.cpp \ - android_media_MediaRecorder.cpp \ - android_media_MediaScanner.cpp \ - android_media_MediaMetadataRetriever.cpp \ - android_media_AmrInputStream.cpp \ - android_media_ResampleInputStream.cpp + android_media_MediaPlayer.cpp \ + android_media_MediaRecorder.cpp \ + android_media_MediaScanner.cpp \ + android_media_MediaMetadataRetriever.cpp \ + android_media_AmrInputStream.cpp \ + android_media_ResampleInputStream.cpp LOCAL_SHARED_LIBRARIES := \ - libopencoreplayer \ - libopencoreauthor \ - libandroid_runtime \ - libnativehelper \ - libcutils \ - libutils \ - libmedia \ - libsgl \ - libui + libopencore_player \ + libopencore_author \ + libomx_amrenc_sharedlibrary \ + libandroid_runtime \ + libnativehelper \ + libcutils \ + libutils \ + libmedia \ + libsgl \ + libui LOCAL_STATIC_LIBRARIES := LOCAL_C_INCLUDES += \ - external/tremor/Tremor \ - $(PV_INCLUDES) \ - $(JNI_H_INCLUDE) \ - $(call include-path-for, corecg graphics) + external/tremor/Tremor \ + $(PV_INCLUDES) \ + $(JNI_H_INCLUDE) \ + $(call include-path-for, corecg graphics) LOCAL_CFLAGS += diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp index 978c1100a3f4222cc9bd439f1ca5f1130ccaf1e6..51cb6c78735c702493e2f8e9c0186173b9108b7c 100644 --- a/media/jni/android_media_AmrInputStream.cpp +++ b/media/jni/android_media_AmrInputStream.cpp @@ -74,7 +74,7 @@ static void android_media_AmrInputStream_GsmAmrEncoderInitialize encodeProps.iInNumChannels = 1; encodeProps.iInInterleaveMode = TEncodeProperties::EINTERLEAVE_LR; encodeProps.iMode = CPvGsmAmrEncoder::GSM_AMR_12_2; - encodeProps.iBitStreamFormatIf2 = false; + encodeProps.iBitStreamFormat = false; encodeProps.iAudioObjectType = 0; encodeProps.iOutSamplingRate = encodeProps.iInSamplingRate; encodeProps.iOutNumChannels = encodeProps.iInNumChannels; diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 209b09f7c2e7f367e5849c03e97d95a5c334ef80..cac65d66600aaf97affbdbe4dece0c7abf687eff 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -150,6 +150,11 @@ static sp setMediaRecorder(JNIEnv* env, jobject thiz, const sp c = get_native_camera(env, camera, NULL); sp mr = getMediaRecorder(env, thiz); process_media_recorder_call(env, mr->setCamera(c->remote()), diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 02731825e08794a17132caed973b6f46486e632a..0812650452bc49a7ff265482ca9ae4c3d107e7e6 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -18,7 +18,8 @@ #define LOG_TAG "SoundPool" #include -//#define USE_SHARED_MEM_BUFFER +// +#define USE_SHARED_MEM_BUFFER // XXX needed for timing latency #include @@ -507,10 +508,12 @@ void SoundChannel::play(const sp& sample, int nextChannelID, float leftV frameCount = sample->size()/numChannels/((sample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)); } +#ifndef USE_SHARED_MEM_BUFFER // Ensure minimum audio buffer size in case of short looped sample if(frameCount < kDefaultBufferCount * bufferFrames) { frameCount = kDefaultBufferCount * bufferFrames; } +#endif AudioTrack* newTrack; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 986f88ee100cdfb90df79fb0b39f7a7ae3fb095f..1720af0a987966a33e0be4973a8cf3181764e03b 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -73,7 +73,6 @@ AudioRecord::~AudioRecord() // Otherwise the callback thread will never exit. stop(); if (mClientRecordThread != 0) { - mCblk->cv.signal(); mClientRecordThread->requestExitAndWait(); mClientRecordThread.clear(); } @@ -96,7 +95,7 @@ status_t AudioRecord::set( { LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount); - if (mAudioFlinger != 0) { + if (mAudioRecord != 0) { return INVALID_OPERATION; } @@ -181,7 +180,6 @@ status_t AudioRecord::set( mStatus = NO_ERROR; - mAudioFlinger = audioFlinger; mAudioRecord = record; mCblkMemory = cblk; mCblk = static_cast(cblk->pointer()); @@ -293,6 +291,7 @@ status_t AudioRecord::stop() } if (android_atomic_and(~1, &mActive) == 1) { + mCblk->cv.signal(); mAudioRecord->stop(); // the record head position will reset to 0, so if a marker is set, we need // to activate it again @@ -375,6 +374,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) status_t result; audio_track_cblk_t* cblk = mCblk; uint32_t framesReq = audioBuffer->frameCount; + uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS; audioBuffer->frameCount = 0; audioBuffer->size = 0; @@ -391,9 +391,9 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) if (UNLIKELY(!waitCount)) return WOULD_BLOCK; timeout = 0; - result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS)); + result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); if (__builtin_expect(result!=NO_ERROR, false)) { - cblk->waitTimeMs += WAIT_PERIOD_MS; + cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { LOGW( "obtainBuffer timed out (is the CPU pegged?) " "user=%08x, server=%08x", cblk->user, cblk->server); @@ -520,7 +520,7 @@ bool AudioRecord::processAudioBuffer(const sp& thread) status_t err = obtainBuffer(&audioBuffer, 1); if (err < NO_ERROR) { if (err != TIMED_OUT) { - LOGE("Error obtaining an audio buffer, giving up."); + LOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up."); return false; } break; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 24f72816d5f3279cce45cc5f11fd86bdca58385a..289bd7552cbbdb8cd15351e5ff1702ec5bb844ec 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -92,7 +92,6 @@ AudioTrack::~AudioTrack() // Otherwise the callback thread will never exit. stop(); if (mAudioTrackThread != 0) { - mCblk->cv.signal(); mAudioTrackThread->requestExitAndWait(); mAudioTrackThread.clear(); } @@ -117,7 +116,7 @@ status_t AudioTrack::set( LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); - if (mAudioFlinger != 0) { + if (mAudioTrack != 0) { LOGE("Track already in use"); return INVALID_OPERATION; } @@ -228,7 +227,6 @@ status_t AudioTrack::set( mStatus = NO_ERROR; - mAudioFlinger = audioFlinger; mAudioTrack = track; mCblkMemory = cblk; mCblk = static_cast(cblk->pointer()); @@ -357,6 +355,7 @@ void AudioTrack::stop() } if (android_atomic_and(~1, &mActive) == 1) { + mCblk->cv.signal(); mAudioTrack->stop(); // Cancel loops (If we are in the middle of a loop, playback // would not stop until loopCount reaches 0). @@ -596,6 +595,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) status_t result; audio_track_cblk_t* cblk = mCblk; uint32_t framesReq = audioBuffer->frameCount; + uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS; audioBuffer->frameCount = 0; audioBuffer->size = 0; @@ -614,9 +614,9 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) if (UNLIKELY(!waitCount)) return WOULD_BLOCK; timeout = 0; - result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS)); + result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); if (__builtin_expect(result!=NO_ERROR, false)) { - cblk->waitTimeMs += WAIT_PERIOD_MS; + cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { // timing out when a loop has been set and we have already written upto loop end // is a normal condition: no need to wake AudioFlinger up. @@ -798,7 +798,7 @@ bool AudioTrack::processAudioBuffer(const sp& thread) status_t err = obtainBuffer(&audioBuffer, 1); if (err < NO_ERROR) { if (err != TIMED_OUT) { - LOGE("Error obtaining an audio buffer, giving up."); + LOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up."); return false; } break; diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 5cbb25ca1fc95358a15bb901f4114fb130c00774..52bd7d4ebb602432811730bd023622377f3bec1a 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -336,7 +336,7 @@ public: { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - remote()->transact(WAKE_UP, data, &reply); + remote()->transact(WAKE_UP, data, &reply, IBinder::FLAG_ONEWAY); return; } diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp index 5feb11fb10bbe33ff610f40128c516b2a1973aab..9d00aefb4ef6f5cf4c2fd1a2ae76fbd8e08034a6 100644 --- a/media/libmedia/IAudioFlingerClient.cpp +++ b/media/libmedia/IAudioFlingerClient.cpp @@ -43,7 +43,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor()); data.writeInt32((int)enabled); - remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply); + remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); } }; diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index 856059328e4b5f6b1271ba18358a6c4b725ebe10..81ee92c5a1214d2f0f447708d27487d331c243cd 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -24,44 +24,235 @@ #include #include #include +#include #include "media/ToneGenerator.h" + namespace android { + // Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details) -const ToneGenerator::ToneDescriptor - ToneGenerator::toneDescriptors[NUM_TONES] = { - // waveFreq[] segments[] repeatCnt - { { 1336, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_0 - { { 1209, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_1 - { { 1336, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_2 - { { 1477, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_3 - { { 1209, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_4 - { { 1336, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_5 - { { 1477, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_6 - { { 1209, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_7 - { { 1336, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_8 - { { 1477, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_9 - { { 1209, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_S - { { 1477, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_P - { { 1633, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_A - { { 1633, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_B - { { 1633, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_C - { { 1633, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_D - { { 425, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_DIAL - { { 425, 0 }, { 500, 500, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_BUSY - { { 425, 0 }, { 200, 200, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CONGESTION - { { 425, 0 }, { 200, 0 }, 0 }, // TONE_SUP_RADIO_ACK - { { 425, 0 }, { 200, 200, 0 }, 2 }, // TONE_SUP_RADIO_NOTAVAIL - { { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR - { { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING - { { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE - { { 400, 1200, 0 }, { 40, 0 }, 0 }, // TONE_PROP_BEEP - { { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK - { { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK - { { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT - { { 400, 1200, 0 }, { 40, 200, 40, 0 }, 0 } // TONE_PROP_BEEP2 - }; +const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = { + { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }}, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_0 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_1 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_2 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_3 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_4 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_5 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_6 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_7 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_8 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_9 + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_S + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_P + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_A + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_B + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_C + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_DTMF_D + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_SUP_DIAL + { segments: { { duration: 500 , waveFreq: { 425, 0 }}, + { duration: 500, waveFreq: { 0 }}, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_SUP_BUSY + { segments: { { duration: 200, waveFreq: { 425, 0 } }, + { duration: 200, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_SUP_CONGESTION + { segments: { { duration: 200, waveFreq: { 425, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 0, + repeatSegment: 0 }, // TONE_SUP_RADIO_ACK + { segments: { { duration: 200, waveFreq: { 425, 0 }}, + { duration: 200, waveFreq: { 0 }}, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 2, + repeatSegment: 0 }, // TONE_SUP_RADIO_NOTAVAIL + { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }}, + { duration: 1000, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_SUP_ERROR + { segments: { { duration: 200, waveFreq: { 425, 0 } }, + { duration: 600, waveFreq: { 0 } }, + { duration: 200, waveFreq: { 425, 0 } }, + { duration: 3000, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_SUP_CALL_WAITING + { segments: { { duration: 1000, waveFreq: { 425, 0 } }, + { duration: 4000, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_SUP_RINGTONE + { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 0, + repeatSegment: 0 }, // TONE_PROP_BEEP + { segments: { { duration: 100, waveFreq: { 1200, 0 } }, + { duration: 100, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 1, + repeatSegment: 0 }, // TONE_PROP_ACK + { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 0, + repeatSegment: 0 }, // TONE_PROP_NACK + { segments: { { duration: 200, waveFreq: { 400, 1200, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 0, + repeatSegment: 0 }, // TONE_PROP_PROMPT + { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } }, + { duration: 200, waveFreq: { 0 } }, + { duration: 40, waveFreq: { 400, 1200, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 0, + repeatSegment: 0 }, // TONE_PROP_BEEP2 + { segments: { { duration: 250, waveFreq: { 440, 0 } }, + { duration: 250, waveFreq: { 620, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_SUP_INTERCEPT + { segments: { { duration: 250, waveFreq: { 440, 0 } }, + { duration: 250, waveFreq: { 620, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 7, + repeatSegment: 0 }, // TONE_SUP_INTERCEPT_ABBREV + { segments: { { duration: 250, waveFreq: { 480, 620, 0 } }, + { duration: 250, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 7, + repeatSegment: 0 }, // TONE_SUP_CONGESTION_ABBREV + { segments: { { duration: 100, waveFreq: { 350, 440, 0 } }, + { duration: 100, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 2, + repeatSegment: 0 }, // TONE_SUP_CONFIRM + { segments: { { duration: 100, waveFreq: { 480, 0 } }, + { duration: 100, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: 3, + repeatSegment: 0 }, // TONE_SUP_PIP + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_ANSI_DIAL + { segments: { { duration: 500, waveFreq: { 480, 620, 0 } }, + { duration: 500, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_ANSI_BUSY + { segments: { { duration: 250, waveFreq: { 480, 620, 0 } }, + { duration: 250, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_ANSI_CONGESTION + { segments: { { duration: 300, waveFreq: { 440, 0 } }, + { duration: 9700, waveFreq: { 0 } }, + { duration: 100, waveFreq: { 440, 0 } }, + { duration: 100, waveFreq: { 0 } }, + { duration: 100, waveFreq: { 440, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 1 }, // TONE_ANSI_CALL_WAITING + { segments: { { duration: 2000, waveFreq: { 440, 480, 0 } }, + { duration: 4000, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_ANSI_RINGTONE + { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_JAPAN_DIAL + { segments: { { duration: 500, waveFreq: { 400, 0 } }, + { duration: 500, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_JAPAN_BUSY + { segments: { { duration: 1000, waveFreq: { 400, 0 } }, + { duration: 2000, waveFreq: { 0 } }, + { duration: 0 , waveFreq: { 0 }}}, + repeatCnt: ToneGenerator::TONEGEN_INF, + repeatSegment: 0 }, // TONE_JAPAN_RADIO_ACK +}; + +// Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type +// to actual tone for current region. +const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = { + { // ANSI + TONE_ANSI_DIAL, // TONE_SUP_DIAL + TONE_ANSI_BUSY, // TONE_SUP_BUSY + TONE_ANSI_CONGESTION, // TONE_SUP_CONGESTION + TONE_SUP_RADIO_ACK, // TONE_SUP_RADIO_ACK + TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL + TONE_SUP_ERROR, // TONE_SUP_ERROR + TONE_ANSI_CALL_WAITING, // TONE_SUP_CALL_WAITING + TONE_ANSI_RINGTONE // TONE_SUP_RINGTONE + }, + { // JAPAN + TONE_JAPAN_DIAL, // TONE_SUP_DIAL + TONE_JAPAN_BUSY, // TONE_SUP_BUSY + TONE_SUP_CONGESTION, // TONE_SUP_CONGESTION + TONE_JAPAN_RADIO_ACK, // TONE_SUP_RADIO_ACK + TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL + TONE_SUP_ERROR, // TONE_SUP_ERROR + TONE_SUP_CALL_WAITING, // TONE_SUP_CALL_WAITING + TONE_SUP_RINGTONE // TONE_SUP_RINGTONE + } +}; + //////////////////////////////////////////////////////////////////////////////// // ToneGenerator class Implementation @@ -105,6 +296,17 @@ ToneGenerator::ToneGenerator(int streamType, float volume) { // Generate tone by chunks of 20 ms to keep cadencing precision mProcessSize = (mSamplingRate * 20) / 1000; + char value[PROPERTY_VALUE_MAX]; + property_get("gsm.operator.iso-country", value, ""); + if (strcmp(value,"us") == 0 || + strcmp(value,"ca") == 0) { + mRegion = ANSI; + } else if (strcmp(value,"jp") == 0) { + mRegion = JAPAN; + } else { + mRegion = CEPT; + } + if (initAudioTrack()) { LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000)); } else { @@ -155,7 +357,7 @@ ToneGenerator::~ToneGenerator() { bool ToneGenerator::startTone(int toneType) { bool lResult = false; - if (toneType >= NUM_TONES) + if ((toneType < 0) || (toneType >= NUM_TONES)) return lResult; if (mState == TONE_IDLE) { @@ -170,7 +372,8 @@ bool ToneGenerator::startTone(int toneType) { mLock.lock(); // Get descriptor for requested tone - mpNewToneDesc = &toneDescriptors[toneType]; + toneType = getToneForRegion(toneType); + mpNewToneDesc = &sToneDescriptors[toneType]; if (mState == TONE_INIT) { if (prepareWave()) { @@ -333,6 +536,7 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) { ToneGenerator *lpToneGen = static_cast(user); short *lpOut = buffer->i16; unsigned int lNumSmp = buffer->size/sizeof(short); + const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc; if (buffer->size == 0) return; @@ -377,7 +581,7 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) { // Exit if tone sequence is over - if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) { + if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) { if (lpToneGen->mState == TONE_PLAYING) { lpToneGen->mState = TONE_STOPPING; } @@ -390,52 +594,64 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) { LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000)); lGenSmp = lReqSmp; - - if (lpToneGen->mCurSegment & 0x0001) { - // If odd segment, OFF -> ON transition : reset wave generator - lWaveCmd = WaveGenerator::WAVEGEN_START; - - LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp); - } else { - // If even segment, ON -> OFF transition : ramp volume down + + // If segment, ON -> OFF transition : ramp volume down + if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) { lWaveCmd = WaveGenerator::WAVEGEN_STOP; - + unsigned int lFreqIdx = 0; + unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx]; + + while (lFrequency != 0) { + WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency); + lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd); + lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx]; + } LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp); } - - // Pre increment segment index and handle loop if last segment reached - if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) { + + // Go to next segment + lpToneGen->mCurSegment++; + + // Handle loop if last segment reached + if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) { LOGV("Last Seg: %d\n", lpToneGen->mCurSegment); // Pre increment loop count and restart if total count not reached. Stop sequence otherwise - if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) { + if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) { LOGV("Repeating Count: %d\n", lpToneGen->mCurCount); - lpToneGen->mCurSegment = 0; + lpToneGen->mCurSegment = lpToneDesc->repeatSegment; + if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) { + lWaveCmd = WaveGenerator::WAVEGEN_START; + } LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment, (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate); } else { + lGenSmp = 0; LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000)); - - // Cancel OFF->ON transition in case previous segment tone state was OFF - if (!(lpToneGen->mCurSegment & 0x0001)) { - lGenSmp = 0; - } } } else { LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment, (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate); + if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) { + // If next segment is not silent, OFF -> ON transition : reset wave generator + lWaveCmd = WaveGenerator::WAVEGEN_START; + + LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp); + } else { + lGenSmp = 0; + } } // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more lpToneGen->mNextSegSmp - += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000; + += (lpToneDesc->segments[lpToneGen->mCurSegment].duration * lpToneGen->mSamplingRate) / 1000; } else { // Inside a segment keep tone ON or OFF - if (lpToneGen->mCurSegment & 0x0001) { + if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] == 0) { lGenSmp = 0; // If odd segment, tone is currently OFF } else { lGenSmp = lReqSmp; // If event segment, tone is currently ON @@ -444,11 +660,13 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) { if (lGenSmp) { // If samples must be generated, call all active wave generators and acumulate waves in lpOut - unsigned int lWaveIdx; + unsigned int lFreqIdx = 0; + unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx]; - for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) { - WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx]; + while (lFrequency != 0) { + WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency); lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd); + lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx]; } } @@ -501,7 +719,7 @@ audioCallback_EndLoop: // Method: ToneGenerator::prepareWave() // // Description: Prepare wave generators and reset tone sequencer state machine. -// mpNewToneDesc must have been initialized befoire calling this function. +// mpNewToneDesc must have been initialized before calling this function. // Input: // none // @@ -510,40 +728,48 @@ audioCallback_EndLoop: // //////////////////////////////////////////////////////////////////////////////// bool ToneGenerator::prepareWave() { - unsigned int lCnt = 0; - unsigned int lNumWaves; + unsigned int segmentIdx = 0; if (!mpNewToneDesc) { return false; } + // Remove existing wave generators if any clearWaveGens(); mpToneDesc = mpNewToneDesc; - // Get total number of sine waves: needed to adapt sine wave gain. - lNumWaves = numWaves(); - - // Instantiate as many wave generators as listed in descriptor - while (lCnt < lNumWaves) { - ToneGenerator::WaveGenerator *lpWaveGen = - new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate, - mpToneDesc->waveFreq[lCnt], - TONEGEN_GAIN/lNumWaves); - if (lpWaveGen == 0) { - goto prepareWave_exit; + while (mpToneDesc->segments[segmentIdx].duration) { + // Get total number of sine waves: needed to adapt sine wave gain. + unsigned int lNumWaves = numWaves(segmentIdx); + unsigned int freqIdx = 0; + unsigned int frequency = mpToneDesc->segments[segmentIdx].waveFreq[freqIdx]; + while (frequency) { + // Instantiate a wave generator if ot already done for this frequency + if (mWaveGens.indexOfKey(frequency) == NAME_NOT_FOUND) { + ToneGenerator::WaveGenerator *lpWaveGen = + new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate, + frequency, + TONEGEN_GAIN/lNumWaves); + if (lpWaveGen == 0) { + goto prepareWave_exit; + } + mWaveGens.add(frequency, lpWaveGen); + } + frequency = mpNewToneDesc->segments[segmentIdx].waveFreq[++freqIdx]; } - - mWaveGens.push(lpWaveGen); - LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]); - lCnt++; + segmentIdx++; } // Initialize tone sequencer mTotalSmp = 0; mCurSegment = 0; mCurCount = 0; - mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000; + if (mpToneDesc->segments[0].duration == TONEGEN_INF) { + mNextSegSmp = TONEGEN_INF; + } else{ + mNextSegSmp = (mpToneDesc->segments[0].duration * mSamplingRate) / 1000; + } return true; @@ -559,19 +785,22 @@ prepareWave_exit: // // Method: ToneGenerator::numWaves() // -// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF). +// Description: Count number of sine waves needed to generate a tone segment (e.g 2 for DTMF). // // Input: -// none +// segmentIdx tone segment index // // Output: // returned value: nummber of sine waves // //////////////////////////////////////////////////////////////////////////////// -unsigned int ToneGenerator::numWaves() { +unsigned int ToneGenerator::numWaves(unsigned int segmentIdx) { unsigned int lCnt = 0; - while (mpToneDesc->waveFreq[lCnt]) { + if (mpToneDesc->segments[segmentIdx].duration) { + while (mpToneDesc->segments[segmentIdx].waveFreq[lCnt]) { + lCnt++; + } lCnt++; } @@ -595,10 +824,38 @@ unsigned int ToneGenerator::numWaves() { void ToneGenerator::clearWaveGens() { LOGV("Clearing mWaveGens:"); - while (!mWaveGens.isEmpty()) { - delete mWaveGens.top(); - mWaveGens.pop(); + for (size_t lIdx = 0; lIdx < mWaveGens.size(); lIdx++) { + delete mWaveGens.valueAt(lIdx); } + mWaveGens.clear(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::getToneForRegion() +// +// Description: Get correct ringtone type according to current region. +// The corrected ring tone type is the tone descriptor index in sToneDescriptors[]. +// +// Input: +// none +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +int ToneGenerator::getToneForRegion(int toneType) { + int regionTone; + + if (mRegion == CEPT || toneType < FIRST_SUP_TONE || toneType > LAST_SUP_TONE) { + regionTone = toneType; + } else { + regionTone = sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE]; + } + + LOGV("getToneForRegion, tone %d, region %d, regionTone %d", toneType, mRegion, regionTone); + + return regionTone; } diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index f7109210d85035d5409328b8c817607c58c9a1fb..f7f24903e719b5b73dd5e2b1865e30045b3286f6 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -7,28 +7,28 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - MediaRecorderClient.cpp \ - MediaPlayerService.cpp \ - MetadataRetrieverClient.cpp \ - VorbisPlayer.cpp \ - MidiFile.cpp + MediaRecorderClient.cpp \ + MediaPlayerService.cpp \ + MetadataRetrieverClient.cpp \ + VorbisPlayer.cpp \ + MidiFile.cpp ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true) LOCAL_LDLIBS += -ldl -lpthread endif LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libvorbisidec \ - libsonivox \ - libopencoreplayer \ - libopencoreauthor \ - libmedia \ - libandroid_runtime + libcutils \ + libutils \ + libvorbisidec \ + libsonivox \ + libopencore_player \ + libopencore_author \ + libmedia \ + libandroid_runtime LOCAL_C_INCLUDES := external/tremor/Tremor \ - $(call include-path-for, graphics corecg) + $(call include-path-for, graphics corecg) LOCAL_MODULE:= libmediaplayerservice diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index d03caa5e5d9fa562e27f46b4ae264a28a929eb13..e9cbb979d2529a7cfc1b65db2caa04658d8c1ad1 100644 --- a/media/libmediaplayerservice/MidiFile.cpp +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -89,7 +89,7 @@ MidiFile::MidiFile() : // create playback thread { Mutex::Autolock l(mMutex); - createThreadEtc(renderThread, this, "midithread"); + createThreadEtc(renderThread, this, "midithread", ANDROID_PRIORITY_AUDIO); mCondition.wait(mMutex); LOGV("thread started"); } diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp index 0ad335f84d10712d0a97ecb2afb8079d77e95b0d..14fd6cedcfada27a640b070aad06c1e40afe4968 100644 --- a/media/libmediaplayerservice/VorbisPlayer.cpp +++ b/media/libmediaplayerservice/VorbisPlayer.cpp @@ -67,7 +67,7 @@ void VorbisPlayer::onFirstRef() LOGV("onFirstRef"); // create playback thread Mutex::Autolock l(mMutex); - createThreadEtc(renderThread, this, "vorbis decoder"); + createThreadEtc(renderThread, this, "vorbis decoder", ANDROID_PRIORITY_AUDIO); mCondition.wait(mMutex); if (mRenderTid > 0) { LOGV("render thread(%d) started", mRenderTid); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java index 07b43bb34f107d7ab84eac04fa739d0a3d7f9068..760b6b5134e8ad472c021614e73651e77a6c87d7 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java @@ -380,35 +380,35 @@ public class MediaNames { public static final String META_DATA_MP3 [][] = { {"/sdcard/media_api/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"}, + "ID3V2.3 Title", "1234", "295", "1"}, {"/sdcard/media_api/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/media_api/metaDataTestMedias/MP3/ID3V1.mp3", null, "test ID3V1 Album", "test ID3V1 Artist", - null, null, null, null, "test ID3V1 Title", "1234", "231332", "1"}, + "ID3V2.3 Title", "1234", "287", "1"}, + {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1.mp3", "1", "test ID3V1 Album", "test ID3V1 Artist", + null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1"}, {"/sdcard/media_api/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/media_api/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"}, + "Blues", "ID3V2.3 Title", "1234", "295", "1"}, {"/sdcard/media_api/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"}, + "Blues", "ID3V2.3 Title", "1234", "295", "1"}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album", - "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "321", "1"}, + "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1"}, {"/sdcard/media_api/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"}, + "Blues", "ID3V2.3 Title", "1234", "295", "1"}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album", - "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", null, "321", "1"}, + "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1"}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album", - "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "321", "1"}, + "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1"}, {"/sdcard/media_api/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"}, + "Blues", "ID3V2.3 Title", null, "295", "1"}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null, - null, null, null, null, null, null, "577", "1"} + null, null, null, null, null, null, "295", "1"} }; public static final String META_DATA_OTHERS [][] = { @@ -432,7 +432,7 @@ public class MediaNames { null, null, "2005", "231180", "1"}, {"/sdcard/media_api/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"}, + "41", "Kung Fu Panda", "2008", "5667840", "2"}, {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"}, @@ -464,6 +464,7 @@ public class MediaNames { 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_PORTRAIT_H263 = "/sdcard/QCIF_mp4.3gp"; public static final String RECORDED_HVGA_MP4 = "/sdcard/HVGA_mp4.mp4"; public static final String RECORDED_QVGA_MP4 = "/sdcard/QVGA_mp4.mp4"; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java index caba47c58c388a008478d14a4279041fc0fee326..d9e17ea6436387a517740acf57e5c71fb8b043e6 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java @@ -43,11 +43,13 @@ public class CodecTest { private static MediaPlayer mMediaPlayer; private MediaPlayer.OnPreparedListener mOnPreparedListener; - private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; //10 seconds max. + private static int WAIT_FOR_COMMAND_TO_COMPLETE = 60000; //1 min max. private static boolean mInitialized = false; + private static boolean mPrepareReset = false; private static Looper mLooper = null; private static final Object lock = new Object(); private static final Object prepareDone = new Object(); + private static final Object videoSizeChanged = new Object(); private static boolean onPrepareSuccess = false; @@ -227,28 +229,84 @@ public class CodecTest { mp.pause(); mp.release(); } + + static MediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener = + new MediaPlayer.OnVideoSizeChangedListener() { + public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { + synchronized (videoSizeChanged) { + Log.v(TAG, "sizechanged notification received ..."); + videoSizeChanged.notify(); + } + } + }; + //Register the videoSizeChanged listener 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(); + int videoHeight = 0; + synchronized (lock) { + initializeMessageLooper(); + try { + lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + } catch(Exception e) { + Log.v(TAG, "looper was interrupted."); + return 0; + } + } + try { + mMediaPlayer.setDataSource(filePath); + mMediaPlayer.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); + mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener); + synchronized (videoSizeChanged) { + try { + mMediaPlayer.prepare(); + mMediaPlayer.start(); + videoSizeChanged.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + } catch (Exception e) { + Log.v(TAG, "wait was interrupted"); + } + } + videoHeight = mMediaPlayer.getVideoHeight(); + terminateMessageLooper(); + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + return videoHeight; } + //Register the videoSizeChanged listener 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(); + + synchronized (lock) { + initializeMessageLooper(); + try { + lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + } catch(Exception e) { + Log.v(TAG, "looper was interrupted."); + return 0; + } + } + try { + mMediaPlayer.setDataSource(filePath); + mMediaPlayer.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); + mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener); + synchronized (videoSizeChanged) { + try { + mMediaPlayer.prepare(); + mMediaPlayer.start(); + videoSizeChanged.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + } catch (Exception e) { + Log.v(TAG, "wait was interrupted"); + } + } + videoWidth = mMediaPlayer.getVideoWidth(); + terminateMessageLooper(); + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } return videoWidth; } @@ -622,6 +680,10 @@ public class CodecTest { static MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() { public void onPrepared(MediaPlayer mp) { synchronized (prepareDone) { + if(mPrepareReset){ + Log.v(TAG, "call Reset"); + mMediaPlayer.reset(); + } Log.v(TAG, "notify the prepare callback"); prepareDone.notify(); onPrepareSuccess = true; @@ -629,13 +691,15 @@ public class CodecTest { } }; - public static boolean prepareAsyncCallback(String filePath) throws Exception { - int videoWidth = 0; - int videoHeight = 0; - boolean checkVideoDimension = false; + public static boolean prepareAsyncCallback(String filePath, boolean reset) throws Exception { + //Added the PrepareReset flag which allow us to switch to different + //test case. + if (reset){ + mPrepareReset = true; + } - initializeMessageLooper(); synchronized (lock) { + initializeMessageLooper(); try { lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); } catch(Exception e) { @@ -651,14 +715,10 @@ public class CodecTest { synchronized (prepareDone) { try { prepareDone.wait(WAIT_FOR_COMMAND_TO_COMPLETE); - Log.v(TAG, "setPreview done"); } catch (Exception e) { Log.v(TAG, "wait was interrupted."); } - } - videoWidth = mMediaPlayer.getVideoWidth(); - videoHeight = mMediaPlayer.getVideoHeight(); - + } terminateMessageLooper(); }catch (Exception e){ Log.v(TAG,e.getMessage()); @@ -666,7 +726,7 @@ public class CodecTest { return onPrepareSuccess; } - + } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java index 364e1af3b8f937bfcaf1f0debcaff88002dbb7c2..3715913877e450305bbc84f0dd20d1fb75817e24 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java @@ -170,21 +170,25 @@ public class MediaMetadataTest extends AndroidTestCase { validateMetatData(non_mp3_test_file.WAV.ordinal(), MediaNames.META_DATA_OTHERS); } + @Suppress @MediumTest public static void testWma9_Metadata() throws Exception { validateMetatData(non_mp3_test_file.WMA9.ordinal(), MediaNames.META_DATA_OTHERS); } + @Suppress @MediumTest public static void testWma10_Metadata() throws Exception { validateMetatData(non_mp3_test_file.WMA10.ordinal(), MediaNames.META_DATA_OTHERS); } + @Suppress @MediumTest public static void testWmv9_Metadata() throws Exception { validateMetatData(non_mp3_test_file.WMV9.ordinal(), MediaNames.META_DATA_OTHERS); } + @Suppress @MediumTest public static void testWmv10_Metadata() throws Exception { validateMetatData(non_mp3_test_file.WMV7.ordinal(), MediaNames.META_DATA_OTHERS); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java index ee6a727dadb73fa969c5c6b1d617e6ea38b5cf96..8be7058babf70fdbfe4109beb63798493c416ada 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java @@ -78,6 +78,7 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase= 0)) { + _colorPointer = pointer; + } + } + + // C function void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) + + public static native void glCompressedTexImage2D( + int target, + int level, + int internalformat, + int width, + int height, + int border, + int imageSize, + java.nio.Buffer data + ); + + // C function void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) + + public static native void glCompressedTexSubImage2D( + int target, + int level, + int xoffset, + int yoffset, + int width, + int height, + int format, + int imageSize, + java.nio.Buffer data + ); + + // C function void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) + + public static native void glCopyTexImage2D( + int target, + int level, + int internalformat, + int x, + int y, + int width, + int height, + int border + ); + + // C function void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) + + public static native void glCopyTexSubImage2D( + int target, + int level, + int xoffset, + int yoffset, + int x, + int y, + int width, + int height + ); + + // C function void glCullFace ( GLenum mode ) + + public static native void glCullFace( + int mode + ); + + // C function void glDeleteTextures ( GLsizei n, const GLuint *textures ) + + public static native void glDeleteTextures( + int n, + int[] textures, + int offset + ); + + // C function void glDeleteTextures ( GLsizei n, const GLuint *textures ) + + public static native void glDeleteTextures( + int n, + java.nio.IntBuffer textures + ); + + // C function void glDepthFunc ( GLenum func ) + + public static native void glDepthFunc( + int func + ); + + // C function void glDepthMask ( GLboolean flag ) + + public static native void glDepthMask( + boolean flag + ); + + // C function void glDepthRangef ( GLclampf zNear, GLclampf zFar ) + + public static native void glDepthRangef( + float zNear, + float zFar + ); + + // C function void glDepthRangex ( GLclampx zNear, GLclampx zFar ) + + public static native void glDepthRangex( + int zNear, + int zFar + ); + + // C function void glDisable ( GLenum cap ) + + public static native void glDisable( + int cap + ); + + // C function void glDisableClientState ( GLenum array ) + + public static native void glDisableClientState( + int array + ); + + // C function void glDrawArrays ( GLenum mode, GLint first, GLsizei count ) + + public static native void glDrawArrays( + int mode, + int first, + int count + ); + + // C function void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) + + public static native void glDrawElements( + int mode, + int count, + int type, + java.nio.Buffer indices + ); + + // C function void glEnable ( GLenum cap ) + + public static native void glEnable( + int cap + ); + + // C function void glEnableClientState ( GLenum array ) + + public static native void glEnableClientState( + int array + ); + + // C function void glFinish ( void ) + + public static native void glFinish( + ); + + // C function void glFlush ( void ) + + public static native void glFlush( + ); + + // C function void glFogf ( GLenum pname, GLfloat param ) + + public static native void glFogf( + int pname, + float param + ); + + // C function void glFogfv ( GLenum pname, const GLfloat *params ) + + public static native void glFogfv( + int pname, + float[] params, + int offset + ); + + // C function void glFogfv ( GLenum pname, const GLfloat *params ) + + public static native void glFogfv( + int pname, + java.nio.FloatBuffer params + ); + + // C function void glFogx ( GLenum pname, GLfixed param ) + + public static native void glFogx( + int pname, + int param + ); + + // C function void glFogxv ( GLenum pname, const GLfixed *params ) + + public static native void glFogxv( + int pname, + int[] params, + int offset + ); + + // C function void glFogxv ( GLenum pname, const GLfixed *params ) + + public static native void glFogxv( + int pname, + java.nio.IntBuffer params + ); + + // C function void glFrontFace ( GLenum mode ) + + public static native void glFrontFace( + int mode + ); + + // C function void glFrustumf ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) + + public static native void glFrustumf( + float left, + float right, + float bottom, + float top, + float zNear, + float zFar + ); + + // C function void glFrustumx ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) + + public static native void glFrustumx( + int left, + int right, + int bottom, + int top, + int zNear, + int zFar + ); + + // C function void glGenTextures ( GLsizei n, GLuint *textures ) + + public static native void glGenTextures( + int n, + int[] textures, + int offset + ); + + // C function void glGenTextures ( GLsizei n, GLuint *textures ) + + public static native void glGenTextures( + int n, + java.nio.IntBuffer textures + ); + + // C function GLenum glGetError ( void ) + + public static native int glGetError( + ); + + // C function void glGetIntegerv ( GLenum pname, GLint *params ) + + public static native void glGetIntegerv( + int pname, + int[] params, + int offset + ); + + // C function void glGetIntegerv ( GLenum pname, GLint *params ) + + public static native void glGetIntegerv( + int pname, + java.nio.IntBuffer params + ); + + // C function const GLubyte * glGetString ( GLenum name ) + + public static native String glGetString( + int name + ); + // C function void glHint ( GLenum target, GLenum mode ) + + public static native void glHint( + int target, + int mode + ); + + // C function void glLightModelf ( GLenum pname, GLfloat param ) + + public static native void glLightModelf( + int pname, + float param + ); + + // C function void glLightModelfv ( GLenum pname, const GLfloat *params ) + + public static native void glLightModelfv( + int pname, + float[] params, + int offset + ); + + // C function void glLightModelfv ( GLenum pname, const GLfloat *params ) + + public static native void glLightModelfv( + int pname, + java.nio.FloatBuffer params + ); + + // C function void glLightModelx ( GLenum pname, GLfixed param ) + + public static native void glLightModelx( + int pname, + int param + ); + + // C function void glLightModelxv ( GLenum pname, const GLfixed *params ) + + public static native void glLightModelxv( + int pname, + int[] params, + int offset + ); + + // C function void glLightModelxv ( GLenum pname, const GLfixed *params ) + + public static native void glLightModelxv( + int pname, + java.nio.IntBuffer params + ); + + // C function void glLightf ( GLenum light, GLenum pname, GLfloat param ) + + public static native void glLightf( + int light, + int pname, + float param + ); + + // C function void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) + + public static native void glLightfv( + int light, + int pname, + float[] params, + int offset + ); + + // C function void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) + + public static native void glLightfv( + int light, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glLightx ( GLenum light, GLenum pname, GLfixed param ) + + public static native void glLightx( + int light, + int pname, + int param + ); + + // C function void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) + + public static native void glLightxv( + int light, + int pname, + int[] params, + int offset + ); + + // C function void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) + + public static native void glLightxv( + int light, + int pname, + java.nio.IntBuffer params + ); + + // C function void glLineWidth ( GLfloat width ) + + public static native void glLineWidth( + float width + ); + + // C function void glLineWidthx ( GLfixed width ) + + public static native void glLineWidthx( + int width + ); + + // C function void glLoadIdentity ( void ) + + public static native void glLoadIdentity( + ); + + // C function void glLoadMatrixf ( const GLfloat *m ) + + public static native void glLoadMatrixf( + float[] m, + int offset + ); + + // C function void glLoadMatrixf ( const GLfloat *m ) + + public static native void glLoadMatrixf( + java.nio.FloatBuffer m + ); + + // C function void glLoadMatrixx ( const GLfixed *m ) + + public static native void glLoadMatrixx( + int[] m, + int offset + ); + + // C function void glLoadMatrixx ( const GLfixed *m ) + + public static native void glLoadMatrixx( + java.nio.IntBuffer m + ); + + // C function void glLogicOp ( GLenum opcode ) + + public static native void glLogicOp( + int opcode + ); + + // C function void glMaterialf ( GLenum face, GLenum pname, GLfloat param ) + + public static native void glMaterialf( + int face, + int pname, + float param + ); + + // C function void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) + + public static native void glMaterialfv( + int face, + int pname, + float[] params, + int offset + ); + + // C function void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) + + public static native void glMaterialfv( + int face, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glMaterialx ( GLenum face, GLenum pname, GLfixed param ) + + public static native void glMaterialx( + int face, + int pname, + int param + ); + + // C function void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) + + public static native void glMaterialxv( + int face, + int pname, + int[] params, + int offset + ); + + // C function void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) + + public static native void glMaterialxv( + int face, + int pname, + java.nio.IntBuffer params + ); + + // C function void glMatrixMode ( GLenum mode ) + + public static native void glMatrixMode( + int mode + ); + + // C function void glMultMatrixf ( const GLfloat *m ) + + public static native void glMultMatrixf( + float[] m, + int offset + ); + + // C function void glMultMatrixf ( const GLfloat *m ) + + public static native void glMultMatrixf( + java.nio.FloatBuffer m + ); + + // C function void glMultMatrixx ( const GLfixed *m ) + + public static native void glMultMatrixx( + int[] m, + int offset + ); + + // C function void glMultMatrixx ( const GLfixed *m ) + + public static native void glMultMatrixx( + java.nio.IntBuffer m + ); + + // C function void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) + + public static native void glMultiTexCoord4f( + int target, + float s, + float t, + float r, + float q + ); + + // C function void glMultiTexCoord4x ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) + + public static native void glMultiTexCoord4x( + int target, + int s, + int t, + int r, + int q + ); + + // C function void glNormal3f ( GLfloat nx, GLfloat ny, GLfloat nz ) + + public static native void glNormal3f( + float nx, + float ny, + float nz + ); + + // C function void glNormal3x ( GLfixed nx, GLfixed ny, GLfixed nz ) + + public static native void glNormal3x( + int nx, + int ny, + int nz + ); + + // C function void glNormalPointer ( GLenum type, GLsizei stride, const GLvoid *pointer ) + + private static native void glNormalPointerBounds( + int type, + int stride, + java.nio.Buffer pointer, + int remaining + ); + + public static void glNormalPointer( + int type, + int stride, + java.nio.Buffer pointer + ) { + glNormalPointerBounds( + type, + stride, + pointer, + pointer.remaining() + ); + if (((type == GL_FLOAT) || + (type == GL_BYTE) || + (type == GL_SHORT) || + (type == GL_FIXED)) && + (stride >= 0)) { + _normalPointer = pointer; + } + } + + // C function void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) + + public static native void glOrthof( + float left, + float right, + float bottom, + float top, + float zNear, + float zFar + ); + + // C function void glOrthox ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) + + public static native void glOrthox( + int left, + int right, + int bottom, + int top, + int zNear, + int zFar + ); + + // C function void glPixelStorei ( GLenum pname, GLint param ) + + public static native void glPixelStorei( + int pname, + int param + ); + + // C function void glPointSize ( GLfloat size ) + + public static native void glPointSize( + float size + ); + + // C function void glPointSizex ( GLfixed size ) + + public static native void glPointSizex( + int size + ); + + // C function void glPolygonOffset ( GLfloat factor, GLfloat units ) + + public static native void glPolygonOffset( + float factor, + float units + ); + + // C function void glPolygonOffsetx ( GLfixed factor, GLfixed units ) + + public static native void glPolygonOffsetx( + int factor, + int units + ); + + // C function void glPopMatrix ( void ) + + public static native void glPopMatrix( + ); + + // C function void glPushMatrix ( void ) + + public static native void glPushMatrix( + ); + + // C function void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) + + public static native void glReadPixels( + int x, + int y, + int width, + int height, + int format, + int type, + java.nio.Buffer pixels + ); + + // C function void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) + + public static native void glRotatef( + float angle, + float x, + float y, + float z + ); + + // C function void glRotatex ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) + + public static native void glRotatex( + int angle, + int x, + int y, + int z + ); + + // C function void glSampleCoverage ( GLclampf value, GLboolean invert ) + + public static native void glSampleCoverage( + float value, + boolean invert + ); + + // C function void glSampleCoveragex ( GLclampx value, GLboolean invert ) + + public static native void glSampleCoveragex( + int value, + boolean invert + ); + + // C function void glScalef ( GLfloat x, GLfloat y, GLfloat z ) + + public static native void glScalef( + float x, + float y, + float z + ); + + // C function void glScalex ( GLfixed x, GLfixed y, GLfixed z ) + + public static native void glScalex( + int x, + int y, + int z + ); + + // C function void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height ) + + public static native void glScissor( + int x, + int y, + int width, + int height + ); + + // C function void glShadeModel ( GLenum mode ) + + public static native void glShadeModel( + int mode + ); + + // C function void glStencilFunc ( GLenum func, GLint ref, GLuint mask ) + + public static native void glStencilFunc( + int func, + int ref, + int mask + ); + + // C function void glStencilMask ( GLuint mask ) + + public static native void glStencilMask( + int mask + ); + + // C function void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass ) + + public static native void glStencilOp( + int fail, + int zfail, + int zpass + ); + + // C function void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) + + private static native void glTexCoordPointerBounds( + int size, + int type, + int stride, + java.nio.Buffer pointer, + int remaining + ); + + public static void glTexCoordPointer( + int size, + int type, + int stride, + java.nio.Buffer pointer + ) { + glTexCoordPointerBounds( + size, + type, + stride, + pointer, + pointer.remaining() + ); + if (((size == 2) || + (size == 3) || + (size == 4)) && + ((type == GL_FLOAT) || + (type == GL_BYTE) || + (type == GL_SHORT) || + (type == GL_FIXED)) && + (stride >= 0)) { + _texCoordPointer = pointer; + } + } + + // C function void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) + + public static native void glTexEnvf( + int target, + int pname, + float param + ); + + // C function void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) + + public static native void glTexEnvfv( + int target, + int pname, + float[] params, + int offset + ); + + // C function void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) + + public static native void glTexEnvfv( + int target, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glTexEnvx ( GLenum target, GLenum pname, GLfixed param ) + + public static native void glTexEnvx( + int target, + int pname, + int param + ); + + // C function void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexEnvxv( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexEnvxv( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) + + public static native void glTexImage2D( + int target, + int level, + int internalformat, + int width, + int height, + int border, + int format, + int type, + java.nio.Buffer pixels + ); + + // C function void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) + + public static native void glTexParameterf( + int target, + int pname, + float param + ); + + // C function void glTexParameterx ( GLenum target, GLenum pname, GLfixed param ) + + public static native void glTexParameterx( + int target, + int pname, + int param + ); + + // C function void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) + + public static native void glTexSubImage2D( + int target, + int level, + int xoffset, + int yoffset, + int width, + int height, + int format, + int type, + java.nio.Buffer pixels + ); + + // C function void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) + + public static native void glTranslatef( + float x, + float y, + float z + ); + + // C function void glTranslatex ( GLfixed x, GLfixed y, GLfixed z ) + + public static native void glTranslatex( + int x, + int y, + int z + ); + + // C function void glVertexPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) + + private static native void glVertexPointerBounds( + int size, + int type, + int stride, + java.nio.Buffer pointer, + int remaining + ); + + public static void glVertexPointer( + int size, + int type, + int stride, + java.nio.Buffer pointer + ) { + glVertexPointerBounds( + size, + type, + stride, + pointer, + pointer.remaining() + ); + if (((size == 2) || + (size == 3) || + (size == 4)) && + ((type == GL_FLOAT) || + (type == GL_BYTE) || + (type == GL_SHORT) || + (type == GL_FIXED)) && + (stride >= 0)) { + _vertexPointer = pointer; + } + } + + // C function void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) + + public static native void glViewport( + int x, + int y, + int width, + int height + ); + +} diff --git a/opengl/java/android/opengl/GLES10Ext.java b/opengl/java/android/opengl/GLES10Ext.java new file mode 100644 index 0000000000000000000000000000000000000000..81fc59e08911653e2d08941929f0c16fb2f888ba --- /dev/null +++ b/opengl/java/android/opengl/GLES10Ext.java @@ -0,0 +1,44 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +public class GLES10Ext { + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + + // C function GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) + + public static native int glQueryMatrixxOES( + int[] mantissa, + int mantissaOffset, + int[] exponent, + int exponentOffset + ); + + // C function GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) + + public static native int glQueryMatrixxOES( + java.nio.IntBuffer mantissa, + java.nio.IntBuffer exponent + ); + +} diff --git a/opengl/java/android/opengl/GLES11.java b/opengl/java/android/opengl/GLES11.java new file mode 100644 index 0000000000000000000000000000000000000000..3399af7834c77d9b8bb5a62b1726c19b01a43263 --- /dev/null +++ b/opengl/java/android/opengl/GLES11.java @@ -0,0 +1,707 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +import java.nio.Buffer; + +public class GLES11 extends GLES10 { + public static final int GL_ACTIVE_TEXTURE = 0x84E0; + public static final int GL_ADD_SIGNED = 0x8574; + public static final int GL_ALPHA_SCALE = 0x0D1C; + public static final int GL_ALPHA_TEST_FUNC = 0x0BC1; + public static final int GL_ALPHA_TEST_REF = 0x0BC2; + public static final int GL_ARRAY_BUFFER = 0x8892; + public static final int GL_ARRAY_BUFFER_BINDING = 0x8894; + public static final int GL_BLEND_DST = 0x0BE0; + public static final int GL_BLEND_SRC = 0x0BE1; + public static final int GL_BUFFER_ACCESS = 0x88BB; + public static final int GL_BUFFER_SIZE = 0x8764; + public static final int GL_BUFFER_USAGE = 0x8765; + public static final int GL_CLIENT_ACTIVE_TEXTURE = 0x84E1; + public static final int GL_CLIP_PLANE0 = 0x3000; + public static final int GL_CLIP_PLANE1 = 0x3001; + public static final int GL_CLIP_PLANE2 = 0x3002; + public static final int GL_CLIP_PLANE3 = 0x3003; + public static final int GL_CLIP_PLANE4 = 0x3004; + public static final int GL_CLIP_PLANE5 = 0x3005; + public static final int GL_COLOR_ARRAY_BUFFER_BINDING = 0x8898; + public static final int GL_COLOR_ARRAY_POINTER = 0x8090; + public static final int GL_COLOR_ARRAY_SIZE = 0x8081; + public static final int GL_COLOR_ARRAY_STRIDE = 0x8083; + public static final int GL_COLOR_ARRAY_TYPE = 0x8082; + public static final int GL_COLOR_CLEAR_VALUE = 0x0C22; + public static final int GL_COLOR_WRITEMASK = 0x0C23; + public static final int GL_COMBINE = 0x8570; + public static final int GL_COMBINE_ALPHA = 0x8572; + public static final int GL_COMBINE_RGB = 0x8571; + public static final int GL_CONSTANT = 0x8576; + public static final int GL_COORD_REPLACE_OES = 0x8862; + public static final int GL_CULL_FACE_MODE = 0x0B45; + public static final int GL_CURRENT_COLOR = 0x0B00; + public static final int GL_CURRENT_NORMAL = 0x0B02; + public static final int GL_CURRENT_TEXTURE_COORDS = 0x0B03; + public static final int GL_DEPTH_CLEAR_VALUE = 0x0B73; + public static final int GL_DEPTH_FUNC = 0x0B74; + public static final int GL_DEPTH_RANGE = 0x0B70; + public static final int GL_DEPTH_WRITEMASK = 0x0B72; + public static final int GL_DOT3_RGB = 0x86AE; + public static final int GL_DOT3_RGBA = 0x86AF; + public static final int GL_DYNAMIC_DRAW = 0x88E8; + public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893; + public static final int GL_ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; + public static final int GL_FRONT_FACE = 0x0B46; + public static final int GL_GENERATE_MIPMAP = 0x8191; + public static final int GL_GENERATE_MIPMAP_HINT = 0x8192; + public static final int GL_INTERPOLATE = 0x8575; + public static final int GL_LINE_WIDTH = 0x0B21; + public static final int GL_LOGIC_OP_MODE = 0x0BF0; + public static final int GL_MATRIX_MODE = 0x0BA0; + public static final int GL_MAX_CLIP_PLANES = 0x0D32; + public static final int GL_MODELVIEW_MATRIX = 0x0BA6; + public static final int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; + public static final int GL_MODELVIEW_STACK_DEPTH = 0x0BA3; + public static final int GL_NORMAL_ARRAY_BUFFER_BINDING = 0x8897; + public static final int GL_NORMAL_ARRAY_POINTER = 0x808F; + public static final int GL_NORMAL_ARRAY_STRIDE = 0x807F; + public static final int GL_NORMAL_ARRAY_TYPE = 0x807E; + public static final int GL_OPERAND0_ALPHA = 0x8598; + public static final int GL_OPERAND0_RGB = 0x8590; + public static final int GL_OPERAND1_ALPHA = 0x8599; + public static final int GL_OPERAND1_RGB = 0x8591; + public static final int GL_OPERAND2_ALPHA = 0x859A; + public static final int GL_OPERAND2_RGB = 0x8592; + public static final int GL_POINT_DISTANCE_ATTENUATION = 0x8129; + public static final int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; + public static final int GL_POINT_SIZE = 0x0B11; + public static final int GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES = 0x8B9F; + public static final int GL_POINT_SIZE_ARRAY_OES = 0x8B9C; + public static final int GL_POINT_SIZE_ARRAY_POINTER_OES = 0x898C; + public static final int GL_POINT_SIZE_ARRAY_STRIDE_OES = 0x898B; + public static final int GL_POINT_SIZE_ARRAY_TYPE_OES = 0x898A; + public static final int GL_POINT_SIZE_MAX = 0x8127; + public static final int GL_POINT_SIZE_MIN = 0x8126; + public static final int GL_POINT_SPRITE_OES = 0x8861; + public static final int GL_POLYGON_OFFSET_FACTOR = 0x8038; + public static final int GL_POLYGON_OFFSET_UNITS = 0x2A00; + public static final int GL_PREVIOUS = 0x8578; + public static final int GL_PRIMARY_COLOR = 0x8577; + public static final int GL_PROJECTION_MATRIX = 0x0BA7; + public static final int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; + public static final int GL_PROJECTION_STACK_DEPTH = 0x0BA4; + public static final int GL_RGB_SCALE = 0x8573; + public static final int GL_SAMPLE_BUFFERS = 0x80A8; + public static final int GL_SAMPLE_COVERAGE_INVERT = 0x80AB; + public static final int GL_SAMPLE_COVERAGE_VALUE = 0x80AA; + public static final int GL_SAMPLES = 0x80A9; + public static final int GL_SCISSOR_BOX = 0x0C10; + public static final int GL_SHADE_MODEL = 0x0B54; + public static final int GL_SRC0_ALPHA = 0x8588; + public static final int GL_SRC0_RGB = 0x8580; + public static final int GL_SRC1_ALPHA = 0x8589; + public static final int GL_SRC1_RGB = 0x8581; + public static final int GL_SRC2_ALPHA = 0x858A; + public static final int GL_SRC2_RGB = 0x8582; + public static final int GL_STATIC_DRAW = 0x88E4; + public static final int GL_STENCIL_CLEAR_VALUE = 0x0B91; + public static final int GL_STENCIL_FAIL = 0x0B94; + public static final int GL_STENCIL_FUNC = 0x0B92; + public static final int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95; + public static final int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96; + public static final int GL_STENCIL_REF = 0x0B97; + public static final int GL_STENCIL_VALUE_MASK = 0x0B93; + public static final int GL_STENCIL_WRITEMASK = 0x0B98; + public static final int GL_SUBTRACT = 0x84E7; + public static final int GL_TEXTURE_BINDING_2D = 0x8069; + public static final int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 0x889A; + public static final int GL_TEXTURE_COORD_ARRAY_POINTER = 0x8092; + public static final int GL_TEXTURE_COORD_ARRAY_SIZE = 0x8088; + public static final int GL_TEXTURE_COORD_ARRAY_STRIDE = 0x808A; + public static final int GL_TEXTURE_COORD_ARRAY_TYPE = 0x8089; + public static final int GL_TEXTURE_MATRIX = 0x0BA8; + public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; + public static final int GL_TEXTURE_STACK_DEPTH = 0x0BA5; + public static final int GL_VERTEX_ARRAY_BUFFER_BINDING = 0x8896; + public static final int GL_VERTEX_ARRAY_POINTER = 0x808E; + public static final int GL_VERTEX_ARRAY_SIZE = 0x807A; + public static final int GL_VERTEX_ARRAY_STRIDE = 0x807C; + public static final int GL_VERTEX_ARRAY_TYPE = 0x807B; + public static final int GL_VIEWPORT = 0x0BA2; + public static final int GL_WRITE_ONLY = 0x88B9; + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + + // C function void glBindBuffer ( GLenum target, GLuint buffer ) + + public static native void glBindBuffer( + int target, + int buffer + ); + + // C function void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) + + public static native void glBufferData( + int target, + int size, + java.nio.Buffer data, + int usage + ); + + // C function void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data ) + + public static native void glBufferSubData( + int target, + int offset, + int size, + java.nio.Buffer data + ); + + // C function void glClipPlanef ( GLenum plane, const GLfloat *equation ) + + public static native void glClipPlanef( + int plane, + float[] equation, + int offset + ); + + // C function void glClipPlanef ( GLenum plane, const GLfloat *equation ) + + public static native void glClipPlanef( + int plane, + java.nio.FloatBuffer equation + ); + + // C function void glClipPlanex ( GLenum plane, const GLfixed *equation ) + + public static native void glClipPlanex( + int plane, + int[] equation, + int offset + ); + + // C function void glClipPlanex ( GLenum plane, const GLfixed *equation ) + + public static native void glClipPlanex( + int plane, + java.nio.IntBuffer equation + ); + + // C function void glColor4ub ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) + + public static native void glColor4ub( + byte red, + byte green, + byte blue, + byte alpha + ); + + // C function void glColorPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) + + public static native void glColorPointer( + int size, + int type, + int stride, + int offset + ); + + // C function void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) + + public static native void glDeleteBuffers( + int n, + int[] buffers, + int offset + ); + + // C function void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) + + public static native void glDeleteBuffers( + int n, + java.nio.IntBuffer buffers + ); + + // C function void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset ) + + public static native void glDrawElements( + int mode, + int count, + int type, + int offset + ); + + // C function void glGenBuffers ( GLsizei n, GLuint *buffers ) + + public static native void glGenBuffers( + int n, + int[] buffers, + int offset + ); + + // C function void glGenBuffers ( GLsizei n, GLuint *buffers ) + + public static native void glGenBuffers( + int n, + java.nio.IntBuffer buffers + ); + + // C function void glGetBooleanv ( GLenum pname, GLboolean *params ) + + public static native void glGetBooleanv( + int pname, + boolean[] params, + int offset + ); + + // C function void glGetBooleanv ( GLenum pname, GLboolean *params ) + + public static native void glGetBooleanv( + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) + + public static native void glGetBufferParameteriv( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) + + public static native void glGetBufferParameteriv( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) + + public static native void glGetClipPlanef( + int pname, + float[] eqn, + int offset + ); + + // C function void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) + + public static native void glGetClipPlanef( + int pname, + java.nio.FloatBuffer eqn + ); + + // C function void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) + + public static native void glGetClipPlanex( + int pname, + int[] eqn, + int offset + ); + + // C function void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) + + public static native void glGetClipPlanex( + int pname, + java.nio.IntBuffer eqn + ); + + // C function void glGetFixedv ( GLenum pname, GLfixed *params ) + + public static native void glGetFixedv( + int pname, + int[] params, + int offset + ); + + // C function void glGetFixedv ( GLenum pname, GLfixed *params ) + + public static native void glGetFixedv( + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetFloatv ( GLenum pname, GLfloat *params ) + + public static native void glGetFloatv( + int pname, + float[] params, + int offset + ); + + // C function void glGetFloatv ( GLenum pname, GLfloat *params ) + + public static native void glGetFloatv( + int pname, + java.nio.FloatBuffer params + ); + + // C function void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) + + public static native void glGetLightfv( + int light, + int pname, + float[] params, + int offset + ); + + // C function void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) + + public static native void glGetLightfv( + int light, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) + + public static native void glGetLightxv( + int light, + int pname, + int[] params, + int offset + ); + + // C function void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) + + public static native void glGetLightxv( + int light, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) + + public static native void glGetMaterialfv( + int face, + int pname, + float[] params, + int offset + ); + + // C function void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) + + public static native void glGetMaterialfv( + int face, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) + + public static native void glGetMaterialxv( + int face, + int pname, + int[] params, + int offset + ); + + // C function void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) + + public static native void glGetMaterialxv( + int face, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexEnvfv ( GLenum env, GLenum pname, GLfloat *params ) + + public static native void glGetTexEnvfv( + int env, + int pname, + float[] params, + int offset + ); + + // C function void glGetTexEnvfv ( GLenum env, GLenum pname, GLfloat *params ) + + public static native void glGetTexEnvfv( + int env, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) + + public static native void glGetTexEnviv( + int env, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) + + public static native void glGetTexEnviv( + int env, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) + + public static native void glGetTexEnvxv( + int env, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) + + public static native void glGetTexEnvxv( + int env, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) + + public static native void glGetTexParameterfv( + int target, + int pname, + float[] params, + int offset + ); + + // C function void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) + + public static native void glGetTexParameterfv( + int target, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) + + public static native void glGetTexParameteriv( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) + + public static native void glGetTexParameteriv( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) + + public static native void glGetTexParameterxv( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) + + public static native void glGetTexParameterxv( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function GLboolean glIsBuffer ( GLuint buffer ) + + public static native boolean glIsBuffer( + int buffer + ); + + // C function GLboolean glIsEnabled ( GLenum cap ) + + public static native boolean glIsEnabled( + int cap + ); + + // C function GLboolean glIsTexture ( GLuint texture ) + + public static native boolean glIsTexture( + int texture + ); + + // C function void glNormalPointer ( GLenum type, GLsizei stride, GLint offset ) + + public static native void glNormalPointer( + int type, + int stride, + int offset + ); + + // C function void glPointParameterf ( GLenum pname, GLfloat param ) + + public static native void glPointParameterf( + int pname, + float param + ); + + // C function void glPointParameterfv ( GLenum pname, const GLfloat *params ) + + public static native void glPointParameterfv( + int pname, + float[] params, + int offset + ); + + // C function void glPointParameterfv ( GLenum pname, const GLfloat *params ) + + public static native void glPointParameterfv( + int pname, + java.nio.FloatBuffer params + ); + + // C function void glPointParameterx ( GLenum pname, GLfixed param ) + + public static native void glPointParameterx( + int pname, + int param + ); + + // C function void glPointParameterxv ( GLenum pname, const GLfixed *params ) + + public static native void glPointParameterxv( + int pname, + int[] params, + int offset + ); + + // C function void glPointParameterxv ( GLenum pname, const GLfixed *params ) + + public static native void glPointParameterxv( + int pname, + java.nio.IntBuffer params + ); + + // C function void glPointSizePointerOES ( GLenum type, GLsizei stride, const GLvoid *pointer ) + + public static native void glPointSizePointerOES( + int type, + int stride, + java.nio.Buffer pointer + ); + + // C function void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) + + public static native void glTexCoordPointer( + int size, + int type, + int stride, + int offset + ); + + // C function void glTexEnvi ( GLenum target, GLenum pname, GLint param ) + + public static native void glTexEnvi( + int target, + int pname, + int param + ); + + // C function void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) + + public static native void glTexEnviv( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) + + public static native void glTexEnviv( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) + + public static native void glTexParameterfv( + int target, + int pname, + float[] params, + int offset + ); + + // C function void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) + + public static native void glTexParameterfv( + int target, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glTexParameteri ( GLenum target, GLenum pname, GLint param ) + + public static native void glTexParameteri( + int target, + int pname, + int param + ); + + // C function void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) + + public static native void glTexParameteriv( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) + + public static native void glTexParameteriv( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexParameterxv( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexParameterxv( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glVertexPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) + + public static native void glVertexPointer( + int size, + int type, + int stride, + int offset + ); + +} diff --git a/opengl/java/android/opengl/GLES11Ext.java b/opengl/java/android/opengl/GLES11Ext.java new file mode 100644 index 0000000000000000000000000000000000000000..4384e9e25af96a0ff26db6edb922a68f7d0bc3b7 --- /dev/null +++ b/opengl/java/android/opengl/GLES11Ext.java @@ -0,0 +1,1076 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +public class GLES11Ext { + public static final int GL_BLEND_EQUATION_RGB_OES = 0x8009; + public static final int GL_BLEND_EQUATION_ALPHA_OES = 0x883D; + public static final int GL_BLEND_DST_RGB_OES = 0x80C8; + public static final int GL_BLEND_SRC_RGB_OES = 0x80C9; + public static final int GL_BLEND_DST_ALPHA_OES = 0x80CA; + public static final int GL_BLEND_SRC_ALPHA_OES = 0x80CB; + public static final int GL_BLEND_EQUATION_OES = 0x8009; + public static final int GL_FUNC_ADD_OES = 0x8006; + public static final int GL_FUNC_SUBTRACT_OES = 0x800A; + public static final int GL_FUNC_REVERSE_SUBTRACT_OES = 0x800B; + public static final int GL_ETC1_RGB8_OES = 0x8D64; + public static final int GL_DEPTH_COMPONENT24_OES = 0x81A6; + public static final int GL_DEPTH_COMPONENT32_OES = 0x81A7; + public static final int GL_TEXTURE_CROP_RECT_OES = 0x8B9D; + public static final int GL_FIXED_OES = 0x140C; + public static final int GL_NONE_OES = 0; + public static final int GL_FRAMEBUFFER_OES = 0x8D40; + public static final int GL_RENDERBUFFER_OES = 0x8D41; + public static final int GL_RGBA4_OES = 0x8056; + public static final int GL_RGB5_A1_OES = 0x8057; + public static final int GL_RGB565_OES = 0x8D62; + public static final int GL_DEPTH_COMPONENT16_OES = 0x81A5; + public static final int GL_RENDERBUFFER_WIDTH_OES = 0x8D42; + public static final int GL_RENDERBUFFER_HEIGHT_OES = 0x8D43; + public static final int GL_RENDERBUFFER_INTERNAL_FORMAT_OES = 0x8D44; + public static final int GL_RENDERBUFFER_RED_SIZE_OES = 0x8D50; + public static final int GL_RENDERBUFFER_GREEN_SIZE_OES = 0x8D51; + public static final int GL_RENDERBUFFER_BLUE_SIZE_OES = 0x8D52; + public static final int GL_RENDERBUFFER_ALPHA_SIZE_OES = 0x8D53; + public static final int GL_RENDERBUFFER_DEPTH_SIZE_OES = 0x8D54; + public static final int GL_RENDERBUFFER_STENCIL_SIZE_OES = 0x8D55; + public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES = 0x8CD0; + public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES = 0x8CD1; + public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES = 0x8CD2; + public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x8CD3; + public static final int GL_COLOR_ATTACHMENT0_OES = 0x8CE0; + public static final int GL_DEPTH_ATTACHMENT_OES = 0x8D00; + public static final int GL_STENCIL_ATTACHMENT_OES = 0x8D20; + public static final int GL_FRAMEBUFFER_COMPLETE_OES = 0x8CD5; + public static final int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES = 0x8CD6; + public static final int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES = 0x8CD7; + public static final int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES = 0x8CD9; + public static final int GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES = 0x8CDA; + public static final int GL_FRAMEBUFFER_UNSUPPORTED_OES = 0x8CDD; + public static final int GL_FRAMEBUFFER_BINDING_OES = 0x8CA6; + public static final int GL_RENDERBUFFER_BINDING_OES = 0x8CA7; + public static final int GL_MAX_RENDERBUFFER_SIZE_OES = 0x84E8; + public static final int GL_INVALID_FRAMEBUFFER_OPERATION_OES = 0x0506; + public static final int GL_WRITE_ONLY_OES = 0x88B9; + public static final int GL_BUFFER_ACCESS_OES = 0x88BB; + public static final int GL_BUFFER_MAPPED_OES = 0x88BC; + public static final int GL_BUFFER_MAP_POINTER_OES = 0x88BD; + public static final int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; + public static final int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; + public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; + public static final int GL_MAX_VERTEX_UNITS_OES = 0x86A4; + public static final int GL_MAX_PALETTE_MATRICES_OES = 0x8842; + public static final int GL_MATRIX_PALETTE_OES = 0x8840; + public static final int GL_MATRIX_INDEX_ARRAY_OES = 0x8844; + public static final int GL_WEIGHT_ARRAY_OES = 0x86AD; + public static final int GL_CURRENT_PALETTE_MATRIX_OES = 0x8843; + public static final int GL_MATRIX_INDEX_ARRAY_SIZE_OES = 0x8846; + public static final int GL_MATRIX_INDEX_ARRAY_TYPE_OES = 0x8847; + public static final int GL_MATRIX_INDEX_ARRAY_STRIDE_OES = 0x8848; + public static final int GL_MATRIX_INDEX_ARRAY_POINTER_OES = 0x8849; + public static final int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x8B9E; + public static final int GL_WEIGHT_ARRAY_SIZE_OES = 0x86AB; + public static final int GL_WEIGHT_ARRAY_TYPE_OES = 0x86A9; + public static final int GL_WEIGHT_ARRAY_STRIDE_OES = 0x86AA; + public static final int GL_WEIGHT_ARRAY_POINTER_OES = 0x86AC; + public static final int GL_WEIGHT_ARRAY_BUFFER_BINDING_OES = 0x889E; + public static final int GL_DEPTH_STENCIL_OES = 0x84F9; + public static final int GL_UNSIGNED_INT_24_8_OES = 0x84FA; + public static final int GL_DEPTH24_STENCIL8_OES = 0x88F0; + public static final int GL_RGB8_OES = 0x8051; + public static final int GL_RGBA8_OES = 0x8058; + public static final int GL_STENCIL_INDEX1_OES = 0x8D46; + public static final int GL_STENCIL_INDEX4_OES = 0x8D47; + public static final int GL_STENCIL_INDEX8_OES = 0x8D48; + public static final int GL_INCR_WRAP_OES = 0x8507; + public static final int GL_DECR_WRAP_OES = 0x8508; + public static final int GL_NORMAL_MAP_OES = 0x8511; + public static final int GL_REFLECTION_MAP_OES = 0x8512; + public static final int GL_TEXTURE_CUBE_MAP_OES = 0x8513; + public static final int GL_TEXTURE_BINDING_CUBE_MAP_OES = 0x8514; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES = 0x8515; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES = 0x8516; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES = 0x8517; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES = 0x8518; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES = 0x8519; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES = 0x851A; + public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES = 0x851C; + public static final int GL_TEXTURE_GEN_MODE_OES = 0x2500; + public static final int GL_TEXTURE_GEN_STR_OES = 0x8D60; + public static final int GL_MIRRORED_REPEAT_OES = 0x8370; + public static final int GL_3DC_X_AMD = 0x87F9; + public static final int GL_3DC_XY_AMD = 0x87FA; + public static final int GL_ATC_RGB_AMD = 0x8C92; + public static final int GL_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93; + public static final int GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE; + public static final int GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; + public static final int GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; + public static final int GL_BGRA = 0x80E1; + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + + // C function void glBlendEquationSeparateOES ( GLenum modeRGB, GLenum modeAlpha ) + + public static native void glBlendEquationSeparateOES( + int modeRGB, + int modeAlpha + ); + + // C function void glBlendFuncSeparateOES ( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) + + public static native void glBlendFuncSeparateOES( + int srcRGB, + int dstRGB, + int srcAlpha, + int dstAlpha + ); + + // C function void glBlendEquationOES ( GLenum mode ) + + public static native void glBlendEquationOES( + int mode + ); + + // C function void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height ) + + public static native void glDrawTexsOES( + short x, + short y, + short z, + short width, + short height + ); + + // C function void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height ) + + public static native void glDrawTexiOES( + int x, + int y, + int z, + int width, + int height + ); + + // C function void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height ) + + public static native void glDrawTexxOES( + int x, + int y, + int z, + int width, + int height + ); + + // C function void glDrawTexsvOES ( const GLshort *coords ) + + public static native void glDrawTexsvOES( + short[] coords, + int offset + ); + + // C function void glDrawTexsvOES ( const GLshort *coords ) + + public static native void glDrawTexsvOES( + java.nio.ShortBuffer coords + ); + + // C function void glDrawTexivOES ( const GLint *coords ) + + public static native void glDrawTexivOES( + int[] coords, + int offset + ); + + // C function void glDrawTexivOES ( const GLint *coords ) + + public static native void glDrawTexivOES( + java.nio.IntBuffer coords + ); + + // C function void glDrawTexxvOES ( const GLfixed *coords ) + + public static native void glDrawTexxvOES( + int[] coords, + int offset + ); + + // C function void glDrawTexxvOES ( const GLfixed *coords ) + + public static native void glDrawTexxvOES( + java.nio.IntBuffer coords + ); + + // C function void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height ) + + public static native void glDrawTexfOES( + float x, + float y, + float z, + float width, + float height + ); + + // C function void glDrawTexfvOES ( const GLfloat *coords ) + + public static native void glDrawTexfvOES( + float[] coords, + int offset + ); + + // C function void glDrawTexfvOES ( const GLfloat *coords ) + + public static native void glDrawTexfvOES( + java.nio.FloatBuffer coords + ); + + // C function void glEGLImageTargetTexture2DOES ( GLenum target, GLeglImageOES image ) + + public static native void glEGLImageTargetTexture2DOES( + int target, + java.nio.Buffer image + ); + + // C function void glEGLImageTargetRenderbufferStorageOES ( GLenum target, GLeglImageOES image ) + + public static native void glEGLImageTargetRenderbufferStorageOES( + int target, + java.nio.Buffer image + ); + + // C function void glAlphaFuncxOES ( GLenum func, GLclampx ref ) + + public static native void glAlphaFuncxOES( + int func, + int ref + ); + + // C function void glClearColorxOES ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) + + public static native void glClearColorxOES( + int red, + int green, + int blue, + int alpha + ); + + // C function void glClearDepthxOES ( GLclampx depth ) + + public static native void glClearDepthxOES( + int depth + ); + + // C function void glClipPlanexOES ( GLenum plane, const GLfixed *equation ) + + public static native void glClipPlanexOES( + int plane, + int[] equation, + int offset + ); + + // C function void glClipPlanexOES ( GLenum plane, const GLfixed *equation ) + + public static native void glClipPlanexOES( + int plane, + java.nio.IntBuffer equation + ); + + // C function void glColor4xOES ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) + + public static native void glColor4xOES( + int red, + int green, + int blue, + int alpha + ); + + // C function void glDepthRangexOES ( GLclampx zNear, GLclampx zFar ) + + public static native void glDepthRangexOES( + int zNear, + int zFar + ); + + // C function void glFogxOES ( GLenum pname, GLfixed param ) + + public static native void glFogxOES( + int pname, + int param + ); + + // C function void glFogxvOES ( GLenum pname, const GLfixed *params ) + + public static native void glFogxvOES( + int pname, + int[] params, + int offset + ); + + // C function void glFogxvOES ( GLenum pname, const GLfixed *params ) + + public static native void glFogxvOES( + int pname, + java.nio.IntBuffer params + ); + + // C function void glFrustumxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) + + public static native void glFrustumxOES( + int left, + int right, + int bottom, + int top, + int zNear, + int zFar + ); + + // C function void glGetClipPlanexOES ( GLenum pname, GLfixed *eqn ) + + public static native void glGetClipPlanexOES( + int pname, + int[] eqn, + int offset + ); + + // C function void glGetClipPlanexOES ( GLenum pname, GLfixed *eqn ) + + public static native void glGetClipPlanexOES( + int pname, + java.nio.IntBuffer eqn + ); + + // C function void glGetFixedvOES ( GLenum pname, GLfixed *params ) + + public static native void glGetFixedvOES( + int pname, + int[] params, + int offset + ); + + // C function void glGetFixedvOES ( GLenum pname, GLfixed *params ) + + public static native void glGetFixedvOES( + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetLightxvOES ( GLenum light, GLenum pname, GLfixed *params ) + + public static native void glGetLightxvOES( + int light, + int pname, + int[] params, + int offset + ); + + // C function void glGetLightxvOES ( GLenum light, GLenum pname, GLfixed *params ) + + public static native void glGetLightxvOES( + int light, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetMaterialxvOES ( GLenum face, GLenum pname, GLfixed *params ) + + public static native void glGetMaterialxvOES( + int face, + int pname, + int[] params, + int offset + ); + + // C function void glGetMaterialxvOES ( GLenum face, GLenum pname, GLfixed *params ) + + public static native void glGetMaterialxvOES( + int face, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexEnvxvOES ( GLenum env, GLenum pname, GLfixed *params ) + + public static native void glGetTexEnvxvOES( + int env, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexEnvxvOES ( GLenum env, GLenum pname, GLfixed *params ) + + public static native void glGetTexEnvxvOES( + int env, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexParameterxvOES ( GLenum target, GLenum pname, GLfixed *params ) + + public static native void glGetTexParameterxvOES( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexParameterxvOES ( GLenum target, GLenum pname, GLfixed *params ) + + public static native void glGetTexParameterxvOES( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glLightModelxOES ( GLenum pname, GLfixed param ) + + public static native void glLightModelxOES( + int pname, + int param + ); + + // C function void glLightModelxvOES ( GLenum pname, const GLfixed *params ) + + public static native void glLightModelxvOES( + int pname, + int[] params, + int offset + ); + + // C function void glLightModelxvOES ( GLenum pname, const GLfixed *params ) + + public static native void glLightModelxvOES( + int pname, + java.nio.IntBuffer params + ); + + // C function void glLightxOES ( GLenum light, GLenum pname, GLfixed param ) + + public static native void glLightxOES( + int light, + int pname, + int param + ); + + // C function void glLightxvOES ( GLenum light, GLenum pname, const GLfixed *params ) + + public static native void glLightxvOES( + int light, + int pname, + int[] params, + int offset + ); + + // C function void glLightxvOES ( GLenum light, GLenum pname, const GLfixed *params ) + + public static native void glLightxvOES( + int light, + int pname, + java.nio.IntBuffer params + ); + + // C function void glLineWidthxOES ( GLfixed width ) + + public static native void glLineWidthxOES( + int width + ); + + // C function void glLoadMatrixxOES ( const GLfixed *m ) + + public static native void glLoadMatrixxOES( + int[] m, + int offset + ); + + // C function void glLoadMatrixxOES ( const GLfixed *m ) + + public static native void glLoadMatrixxOES( + java.nio.IntBuffer m + ); + + // C function void glMaterialxOES ( GLenum face, GLenum pname, GLfixed param ) + + public static native void glMaterialxOES( + int face, + int pname, + int param + ); + + // C function void glMaterialxvOES ( GLenum face, GLenum pname, const GLfixed *params ) + + public static native void glMaterialxvOES( + int face, + int pname, + int[] params, + int offset + ); + + // C function void glMaterialxvOES ( GLenum face, GLenum pname, const GLfixed *params ) + + public static native void glMaterialxvOES( + int face, + int pname, + java.nio.IntBuffer params + ); + + // C function void glMultMatrixxOES ( const GLfixed *m ) + + public static native void glMultMatrixxOES( + int[] m, + int offset + ); + + // C function void glMultMatrixxOES ( const GLfixed *m ) + + public static native void glMultMatrixxOES( + java.nio.IntBuffer m + ); + + // C function void glMultiTexCoord4xOES ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) + + public static native void glMultiTexCoord4xOES( + int target, + int s, + int t, + int r, + int q + ); + + // C function void glNormal3xOES ( GLfixed nx, GLfixed ny, GLfixed nz ) + + public static native void glNormal3xOES( + int nx, + int ny, + int nz + ); + + // C function void glOrthoxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) + + public static native void glOrthoxOES( + int left, + int right, + int bottom, + int top, + int zNear, + int zFar + ); + + // C function void glPointParameterxOES ( GLenum pname, GLfixed param ) + + public static native void glPointParameterxOES( + int pname, + int param + ); + + // C function void glPointParameterxvOES ( GLenum pname, const GLfixed *params ) + + public static native void glPointParameterxvOES( + int pname, + int[] params, + int offset + ); + + // C function void glPointParameterxvOES ( GLenum pname, const GLfixed *params ) + + public static native void glPointParameterxvOES( + int pname, + java.nio.IntBuffer params + ); + + // C function void glPointSizexOES ( GLfixed size ) + + public static native void glPointSizexOES( + int size + ); + + // C function void glPolygonOffsetxOES ( GLfixed factor, GLfixed units ) + + public static native void glPolygonOffsetxOES( + int factor, + int units + ); + + // C function void glRotatexOES ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) + + public static native void glRotatexOES( + int angle, + int x, + int y, + int z + ); + + // C function void glSampleCoveragexOES ( GLclampx value, GLboolean invert ) + + public static native void glSampleCoveragexOES( + int value, + boolean invert + ); + + // C function void glScalexOES ( GLfixed x, GLfixed y, GLfixed z ) + + public static native void glScalexOES( + int x, + int y, + int z + ); + + // C function void glTexEnvxOES ( GLenum target, GLenum pname, GLfixed param ) + + public static native void glTexEnvxOES( + int target, + int pname, + int param + ); + + // C function void glTexEnvxvOES ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexEnvxvOES( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glTexEnvxvOES ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexEnvxvOES( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glTexParameterxOES ( GLenum target, GLenum pname, GLfixed param ) + + public static native void glTexParameterxOES( + int target, + int pname, + int param + ); + + // C function void glTexParameterxvOES ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexParameterxvOES( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glTexParameterxvOES ( GLenum target, GLenum pname, const GLfixed *params ) + + public static native void glTexParameterxvOES( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function void glTranslatexOES ( GLfixed x, GLfixed y, GLfixed z ) + + public static native void glTranslatexOES( + int x, + int y, + int z + ); + + // C function GLboolean glIsRenderbufferOES ( GLuint renderbuffer ) + + public static native boolean glIsRenderbufferOES( + int renderbuffer + ); + + // C function void glBindRenderbufferOES ( GLenum target, GLuint renderbuffer ) + + public static native void glBindRenderbufferOES( + int target, + int renderbuffer + ); + + // C function void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) + + public static native void glDeleteRenderbuffersOES( + int n, + int[] renderbuffers, + int offset + ); + + // C function void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) + + public static native void glDeleteRenderbuffersOES( + int n, + java.nio.IntBuffer renderbuffers + ); + + // C function void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) + + public static native void glGenRenderbuffersOES( + int n, + int[] renderbuffers, + int offset + ); + + // C function void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) + + public static native void glGenRenderbuffersOES( + int n, + java.nio.IntBuffer renderbuffers + ); + + // C function void glRenderbufferStorageOES ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) + + public static native void glRenderbufferStorageOES( + int target, + int internalformat, + int width, + int height + ); + + // C function void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) + + public static native void glGetRenderbufferParameterivOES( + int target, + int pname, + int[] params, + int offset + ); + + // C function void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) + + public static native void glGetRenderbufferParameterivOES( + int target, + int pname, + java.nio.IntBuffer params + ); + + // C function GLboolean glIsFramebufferOES ( GLuint framebuffer ) + + public static native boolean glIsFramebufferOES( + int framebuffer + ); + + // C function void glBindFramebufferOES ( GLenum target, GLuint framebuffer ) + + public static native void glBindFramebufferOES( + int target, + int framebuffer + ); + + // C function void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) + + public static native void glDeleteFramebuffersOES( + int n, + int[] framebuffers, + int offset + ); + + // C function void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) + + public static native void glDeleteFramebuffersOES( + int n, + java.nio.IntBuffer framebuffers + ); + + // C function void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) + + public static native void glGenFramebuffersOES( + int n, + int[] framebuffers, + int offset + ); + + // C function void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) + + public static native void glGenFramebuffersOES( + int n, + java.nio.IntBuffer framebuffers + ); + + // C function GLenum glCheckFramebufferStatusOES ( GLenum target ) + + public static native int glCheckFramebufferStatusOES( + int target + ); + + // C function void glFramebufferRenderbufferOES ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) + + public static native void glFramebufferRenderbufferOES( + int target, + int attachment, + int renderbuffertarget, + int renderbuffer + ); + + // C function void glFramebufferTexture2DOES ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) + + public static native void glFramebufferTexture2DOES( + int target, + int attachment, + int textarget, + int texture, + int level + ); + + // C function void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) + + public static native void glGetFramebufferAttachmentParameterivOES( + int target, + int attachment, + int pname, + int[] params, + int offset + ); + + // C function void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) + + public static native void glGetFramebufferAttachmentParameterivOES( + int target, + int attachment, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGenerateMipmapOES ( GLenum target ) + + public static native void glGenerateMipmapOES( + int target + ); + + // C function void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) + + public static native void glCurrentPaletteMatrixOES( + int matrixpaletteindex + ); + + // C function void glLoadPaletteFromModelViewMatrixOES ( void ) + + public static native void glLoadPaletteFromModelViewMatrixOES( + ); + + // C function void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) + + public static native void glMatrixIndexPointerOES( + int size, + int type, + int stride, + java.nio.Buffer pointer + ); + + // C function void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) + + public static native void glWeightPointerOES( + int size, + int type, + int stride, + java.nio.Buffer pointer + ); + + // C function void glDepthRangefOES ( GLclampf zNear, GLclampf zFar ) + + public static native void glDepthRangefOES( + float zNear, + float zFar + ); + + // C function void glFrustumfOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) + + public static native void glFrustumfOES( + float left, + float right, + float bottom, + float top, + float zNear, + float zFar + ); + + // C function void glOrthofOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) + + public static native void glOrthofOES( + float left, + float right, + float bottom, + float top, + float zNear, + float zFar + ); + + // C function void glClipPlanefOES ( GLenum plane, const GLfloat *equation ) + + public static native void glClipPlanefOES( + int plane, + float[] equation, + int offset + ); + + // C function void glClipPlanefOES ( GLenum plane, const GLfloat *equation ) + + public static native void glClipPlanefOES( + int plane, + java.nio.FloatBuffer equation + ); + + // C function void glGetClipPlanefOES ( GLenum pname, GLfloat *eqn ) + + public static native void glGetClipPlanefOES( + int pname, + float[] eqn, + int offset + ); + + // C function void glGetClipPlanefOES ( GLenum pname, GLfloat *eqn ) + + public static native void glGetClipPlanefOES( + int pname, + java.nio.FloatBuffer eqn + ); + + // C function void glClearDepthfOES ( GLclampf depth ) + + public static native void glClearDepthfOES( + float depth + ); + + // C function void glTexGenfOES ( GLenum coord, GLenum pname, GLfloat param ) + + public static native void glTexGenfOES( + int coord, + int pname, + float param + ); + + // C function void glTexGenfvOES ( GLenum coord, GLenum pname, const GLfloat *params ) + + public static native void glTexGenfvOES( + int coord, + int pname, + float[] params, + int offset + ); + + // C function void glTexGenfvOES ( GLenum coord, GLenum pname, const GLfloat *params ) + + public static native void glTexGenfvOES( + int coord, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glTexGeniOES ( GLenum coord, GLenum pname, GLint param ) + + public static native void glTexGeniOES( + int coord, + int pname, + int param + ); + + // C function void glTexGenivOES ( GLenum coord, GLenum pname, const GLint *params ) + + public static native void glTexGenivOES( + int coord, + int pname, + int[] params, + int offset + ); + + // C function void glTexGenivOES ( GLenum coord, GLenum pname, const GLint *params ) + + public static native void glTexGenivOES( + int coord, + int pname, + java.nio.IntBuffer params + ); + + // C function void glTexGenxOES ( GLenum coord, GLenum pname, GLfixed param ) + + public static native void glTexGenxOES( + int coord, + int pname, + int param + ); + + // C function void glTexGenxvOES ( GLenum coord, GLenum pname, const GLfixed *params ) + + public static native void glTexGenxvOES( + int coord, + int pname, + int[] params, + int offset + ); + + // C function void glTexGenxvOES ( GLenum coord, GLenum pname, const GLfixed *params ) + + public static native void glTexGenxvOES( + int coord, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexGenfvOES ( GLenum coord, GLenum pname, GLfloat *params ) + + public static native void glGetTexGenfvOES( + int coord, + int pname, + float[] params, + int offset + ); + + // C function void glGetTexGenfvOES ( GLenum coord, GLenum pname, GLfloat *params ) + + public static native void glGetTexGenfvOES( + int coord, + int pname, + java.nio.FloatBuffer params + ); + + // C function void glGetTexGenivOES ( GLenum coord, GLenum pname, GLint *params ) + + public static native void glGetTexGenivOES( + int coord, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexGenivOES ( GLenum coord, GLenum pname, GLint *params ) + + public static native void glGetTexGenivOES( + int coord, + int pname, + java.nio.IntBuffer params + ); + + // C function void glGetTexGenxvOES ( GLenum coord, GLenum pname, GLfixed *params ) + + public static native void glGetTexGenxvOES( + int coord, + int pname, + int[] params, + int offset + ); + + // C function void glGetTexGenxvOES ( GLenum coord, GLenum pname, GLfixed *params ) + + public static native void glGetTexGenxvOES( + int coord, + int pname, + java.nio.IntBuffer params + ); + +} diff --git a/opengl/java/android/opengl/GLU.java b/opengl/java/android/opengl/GLU.java index 0152f42b0e418b3b30ad7af6fa82fb959539c99e..49a43d07d9b8a7812f8ad2e8b39b7a88122957c4 100644 --- a/opengl/java/android/opengl/GLU.java +++ b/opengl/java/android/opengl/GLU.java @@ -20,14 +20,14 @@ import javax.microedition.khronos.opengles.GL10; /** * A set of GL utilities inspired by the OpenGL Utility Toolkit. - * + * */ public class GLU { /** * Return an error string from a GL or GLU error code. - * + * * @param error - a GL or GLU error code. * @return the error string for the input error code, or NULL if the input * was not a valid GL or GLU error code. @@ -56,7 +56,7 @@ public class GLU { /** * Define a viewing transformation in terms of an eye point, a center of * view, and an up vector. - * + * * @param gl a GL10 interface * @param eyeX eye point X * @param eyeY eye point Y @@ -89,46 +89,48 @@ public class GLU { 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; float uz = sx * fy - sy * fx; - float[] m = new float[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; - - gl.glMultMatrixf(m, 0); + float[] scratch = sScratch; + synchronized(scratch) { + scratch[0] = sx; + scratch[1] = ux; + scratch[2] = -fx; + scratch[3] = 0.0f; + + scratch[4] = sy; + scratch[5] = uy; + scratch[6] = -fy; + scratch[7] = 0.0f; + + scratch[8] = sz; + scratch[9] = uz; + scratch[10] = -fz; + scratch[11] = 0.0f; + + scratch[12] = 0.0f; + scratch[13] = 0.0f; + scratch[14] = 0.0f; + scratch[15] = 1.0f; + + gl.glMultMatrixf(scratch, 0); + } gl.glTranslatef(-eyeX, -eyeY, -eyeZ); } /** * Set up a 2D orthographic projection matrix - * + * * @param gl * @param left * @param right @@ -142,7 +144,7 @@ public class GLU { /** * Set up a perspective projection matrix - * + * * @param gl a GL10 interface * @param fovy specifies the field of view angle, in degrees, in the Y * direction. @@ -170,7 +172,7 @@ public class GLU { *

        * Note that you can use the OES_matrix_get extension, if present, to get * the current modelView and projection matrices. - * + * * @param objX object coordinates X * @param objY object coordinates Y * @param objZ object coordinates Z @@ -193,35 +195,39 @@ public class GLU { public static int gluProject(float objX, float objY, float objZ, float[] model, int modelOffset, float[] project, int projectOffset, int[] view, int viewOffset, float[] win, int winOffset) { - float[] m = new float[16]; - Matrix.multiplyMM(m, 0, project, projectOffset, model, modelOffset); - - float[] v = new float[4]; - - v[0] = objX; - v[1] = objY; - v[2] = objZ; - v[3] = 1.0f; - - float[] v2 = new float[4]; - - Matrix.multiplyMV(v2, 0, m, 0, v, 0); - - float w = v2[3]; - if (w == 0.0f) { - return GL10.GL_FALSE; + float[] scratch = sScratch; + synchronized(scratch) { + final int M_OFFSET = 0; // 0..15 + final int V_OFFSET = 16; // 16..19 + final int V2_OFFSET = 20; // 20..23 + Matrix.multiplyMM(scratch, M_OFFSET, project, projectOffset, + model, modelOffset); + + scratch[V_OFFSET + 0] = objX; + scratch[V_OFFSET + 1] = objY; + scratch[V_OFFSET + 2] = objZ; + scratch[V_OFFSET + 3] = 1.0f; + + Matrix.multiplyMV(scratch, V2_OFFSET, + scratch, M_OFFSET, scratch, V_OFFSET); + + float w = scratch[V2_OFFSET + 3]; + if (w == 0.0f) { + return GL10.GL_FALSE; + } + + float rw = 1.0f / w; + + win[winOffset] = + view[viewOffset] + view[viewOffset + 2] + * (scratch[V2_OFFSET + 0] * rw + 1.0f) + * 0.5f; + win[winOffset + 1] = + view[viewOffset + 1] + view[viewOffset + 3] + * (scratch[V2_OFFSET + 1] * rw + 1.0f) * 0.5f; + win[winOffset + 2] = (scratch[V2_OFFSET + 2] * rw + 1.0f) * 0.5f; } - float rw = 1.0f / w; - - win[winOffset] = - view[viewOffset] + view[viewOffset + 2] * (v2[0] * rw + 1.0f) - * 0.5f; - win[winOffset + 1] = - view[viewOffset + 1] + view[viewOffset + 3] - * (v2[1] * rw + 1.0f) * 0.5f; - win[winOffset + 2] = (v2[2] * rw + 1.0f) * 0.5f; - return GL10.GL_TRUE; } @@ -232,7 +238,7 @@ public class GLU { *

        * Note that you can use the OES_matrix_get extension, if present, to get * the current modelView and projection matrices. - * + * * @param winX window coordinates X * @param winY window coordinates Y * @param winZ window coordinates Z @@ -255,34 +261,33 @@ public class GLU { public static int gluUnProject(float winX, float winY, float winZ, float[] model, int modelOffset, float[] project, int projectOffset, int[] view, int viewOffset, float[] obj, int objOffset) { - float[] pm = new float[16]; - Matrix.multiplyMM(pm, 0, project, projectOffset, model, modelOffset); - - float[] invPM = new float[16]; - if (!Matrix.invertM(invPM, 0, pm, 0)) { - return GL10.GL_FALSE; + float[] scratch = sScratch; + synchronized(scratch) { + final int PM_OFFSET = 0; // 0..15 + final int INVPM_OFFSET = 16; // 16..31 + final int V_OFFSET = 0; // 0..3 Reuses PM_OFFSET space + Matrix.multiplyMM(scratch, PM_OFFSET, project, projectOffset, + model, modelOffset); + + if (!Matrix.invertM(scratch, INVPM_OFFSET, scratch, PM_OFFSET)) { + return GL10.GL_FALSE; + } + + scratch[V_OFFSET + 0] = + 2.0f * (winX - view[viewOffset + 0]) / view[viewOffset + 2] + - 1.0f; + scratch[V_OFFSET + 1] = + 2.0f * (winY - view[viewOffset + 1]) / view[viewOffset + 3] + - 1.0f; + scratch[V_OFFSET + 2] = 2.0f * winZ - 1.0f; + scratch[V_OFFSET + 3] = 1.0f; + + Matrix.multiplyMV(obj, objOffset, scratch, INVPM_OFFSET, + scratch, V_OFFSET); } - float[] v = new float[4]; - - v[0] = - 2.0f * (winX - view[viewOffset + 0]) / view[viewOffset + 2] - - 1.0f; - v[1] = - 2.0f * (winY - view[viewOffset + 1]) / view[viewOffset + 3] - - 1.0f; - v[2] = 2.0f * winZ - 1.0f; - v[3] = 1.0f; - - float[] v2 = new float[4]; - - Matrix.multiplyMV(v2, 0, invPM, 0, v, 0); - - obj[objOffset] = v2[0]; - obj[objOffset + 1] = v2[1]; - obj[objOffset + 2] = v2[2]; - return GL10.GL_TRUE; } + private static final float[] sScratch = new float[32]; } diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java index 47f07d02f31e368399890c5dffe708c9807fa028..4e365ef86c2e4c73e86639ee0e7d0bbbb23d4ee8 100644 --- a/opengl/java/com/google/android/gles_jni/GLImpl.java +++ b/opengl/java/com/google/android/gles_jni/GLImpl.java @@ -172,13 +172,6 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int stride, java.nio.Buffer pointer ) { - if ((size == 4) && - ((type == GL_FLOAT) || - (type == GL_UNSIGNED_BYTE) || - (type == GL_FIXED)) && - (stride >= 0)) { - _colorPointer = pointer; - } glColorPointerBounds( size, type, @@ -186,6 +179,13 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { pointer, pointer.remaining() ); + if ((size == 4) && + ((type == GL_FLOAT) || + (type == GL_UNSIGNED_BYTE) || + (type == GL_FIXED)) && + (stride >= 0)) { + _colorPointer = pointer; + } } // C function void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) @@ -744,6 +744,12 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int stride, java.nio.Buffer pointer ) { + glNormalPointerBounds( + type, + stride, + pointer, + pointer.remaining() + ); if (((type == GL_FLOAT) || (type == GL_BYTE) || (type == GL_SHORT) || @@ -751,12 +757,6 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { (stride >= 0)) { _normalPointer = pointer; } - glNormalPointerBounds( - type, - stride, - pointer, - pointer.remaining() - ); } // C function void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) @@ -937,6 +937,13 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int stride, java.nio.Buffer pointer ) { + glTexCoordPointerBounds( + size, + type, + stride, + pointer, + pointer.remaining() + ); if (((size == 2) || (size == 3) || (size == 4)) && @@ -947,13 +954,6 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { (stride >= 0)) { _texCoordPointer = pointer; } - glTexCoordPointerBounds( - size, - type, - stride, - pointer, - pointer.remaining() - ); } // C function void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) @@ -1082,6 +1082,13 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int stride, java.nio.Buffer pointer ) { + glVertexPointerBounds( + size, + type, + stride, + pointer, + pointer.remaining() + ); if (((size == 2) || (size == 3) || (size == 4)) && @@ -1092,13 +1099,6 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { (stride >= 0)) { _vertexPointer = pointer; } - glVertexPointerBounds( - size, - type, - stride, - pointer, - pointer.remaining() - ); } // C function void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 99efe4c41de8e30398501bde2ad3d2573fa0cee3..3ce0414d8277c559be6d0e758808f43efce7e8dc 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -33,6 +33,8 @@ ifneq ($(TARGET_SIMULATOR),true) endif LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger +LOCAL_CFLAGS += -fvisibility=hidden + LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE:= libagl diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 3b4c0419f0db7fbce7d63f4ed21e954916120a17..c44478db83beccd31fbd54947d587184b5594a70 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -1,17 +1,17 @@ -/* +/* ** ** 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 +** Licensed under the Apache License Version 2.0(the "License"); +** you may not use this 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. */ @@ -478,22 +478,38 @@ struct extention_map_t { }; static const extention_map_t gExtentionMap[] = { - { "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 }, + { "glDrawTexsOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES }, + { "glDrawTexiOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES }, + { "glDrawTexfOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES }, + { "glDrawTexxOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES }, + { "glDrawTexsvOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES }, + { "glDrawTexivOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES }, + { "glDrawTexfvOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES }, + { "glDrawTexxvOES", + (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES }, + { "glQueryMatrixxOES", + (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES }, + { "glClipPlanef", + (__eglMustCastToProperFunctionPointerType)&glClipPlanef }, + { "glClipPlanex", + (__eglMustCastToProperFunctionPointerType)&glClipPlanex }, + { "glBindBuffer", + (__eglMustCastToProperFunctionPointerType)&glBindBuffer }, + { "glBufferData", + (__eglMustCastToProperFunctionPointerType)&glBufferData }, + { "glBufferSubData", + (__eglMustCastToProperFunctionPointerType)&glBufferSubData }, + { "glDeleteBuffers", + (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers }, + { "glGenBuffers", + (__eglMustCastToProperFunctionPointerType)&glGenBuffers }, }; /* @@ -1299,6 +1315,8 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, } } + // TODO: call connect / disconnect on the surface + ogles_context_t* gl = (ogles_context_t*)ctx; if (makeCurrent(gl) == 0) { if (ctx) { diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index 2ecc7768cac25f4d7cfd08ec8b196d885f26e6ff..5ba6b76c10ecbd97e6c654ead3d57818f4de3224 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -23,6 +23,8 @@ else LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private endif +LOCAL_CFLAGS += -fvisibility=hidden + include $(BUILD_SHARED_LIBRARY) @@ -35,7 +37,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ GLES_CM/gl.cpp.arm \ - GLES_CM/gl_logger.cpp \ # LOCAL_SHARED_LIBRARIES += libcutils libutils libui libEGL @@ -50,4 +51,6 @@ else LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private endif +LOCAL_CFLAGS += -fvisibility=hidden + include $(BUILD_SHARED_LIBRARY) diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 0b4bcce9eae5264512fcde8380a6975a04f2338e..25e31ee7f271814d16c37c529188fae89a016ac4 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -14,7 +14,7 @@ ** limitations under the License. */ -#define LOG_TAG "GLLogger" +#define LOG_TAG "libEGL" #include #include @@ -69,9 +69,9 @@ private: struct egl_display_t : public egl_object_t<'_dpy'> { - EGLDisplay dpys[2]; - EGLConfig* configs[2]; - EGLint numConfigs[2]; + EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; + EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; + EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; EGLint numTotalConfigs; char const* extensionsString; volatile int32_t refs; @@ -81,7 +81,7 @@ struct egl_display_t : public egl_object_t<'_dpy'> char const * clientApi; char const * extensions; }; - strings_t queryString[2]; + strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; }; struct egl_surface_t : public egl_object_t<'_srf'> @@ -143,6 +143,7 @@ static void gl_unimplemented() { static char const * const gl_names[] = { #include "gl_entries.in" + #include "glext_entries.in" NULL }; @@ -156,15 +157,15 @@ static char const * const egl_names[] = { // ---------------------------------------------------------------------------- -egl_connection_t gEGLImpl[2]; +egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS]; static egl_display_t gDisplay[NUM_DISPLAYS]; static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t gEGLThreadLocalStorageKey = -1; // ---------------------------------------------------------------------------- -gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS]; -pthread_key_t gGLWrapperKey = -1; +EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS]; +EGLAPI pthread_key_t gGLWrapperKey = -1; // ---------------------------------------------------------------------------- @@ -272,35 +273,81 @@ int gpu_release(void*, request_gpu_t* gpu); static __attribute__((noinline)) void *load_driver(const char* driver, gl_hooks_t* hooks) { + //LOGD("%s", driver); + char scrap[256]; void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL); LOGE_IF(!dso, "couldn't load <%s> library (%s)", driver, dlerror()); if (dso) { - void** curr; + // first find the symbol for eglGetProcAddress + + typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)( + const char*); + + getProcAddressType getProcAddress = + (getProcAddressType)dlsym(dso, "eglGetProcAddress"); + + LOGE_IF(!getProcAddress, + "can't find eglGetProcAddress() in %s", driver); + + __eglMustCastToProperFunctionPointerType* curr; char const * const * api; - gl_hooks_t::gl_t* gl = &hooks->gl; - curr = (void**)gl; - api = gl_names; + + gl_hooks_t::egl_t* egl = &hooks->egl; + curr = (__eglMustCastToProperFunctionPointerType*)egl; + api = egl_names; while (*api) { - void* f = dlsym(dso, *api); - //LOGD("<%s> @ 0x%p", *api, f); + char const * name = *api; + __eglMustCastToProperFunctionPointerType f = + (__eglMustCastToProperFunctionPointerType)dlsym(dso, name); if (f == NULL) { - //LOGW("<%s> not found in %s", *api, driver); - f = (void*)gl_unimplemented; + // couldn't find the entry-point, use eglGetProcAddress() + f = getProcAddress(name); + if (f == NULL) { + f = (__eglMustCastToProperFunctionPointerType)0; + } } *curr++ = f; api++; } - gl_hooks_t::egl_t* egl = &hooks->egl; - curr = (void**)egl; - api = egl_names; + + gl_hooks_t::gl_t* gl = &hooks->gl; + curr = (__eglMustCastToProperFunctionPointerType*)gl; + api = gl_names; while (*api) { - void* f = dlsym(dso, *api); + char const * name = *api; + __eglMustCastToProperFunctionPointerType f = + (__eglMustCastToProperFunctionPointerType)dlsym(dso, name); + if (f == NULL) { + // couldn't find the entry-point, use eglGetProcAddress() + f = getProcAddress(name); + } + if (f == NULL) { + // Try without the OES postfix + ssize_t index = ssize_t(strlen(name)) - 3; + if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) { + strncpy(scrap, name, index); + scrap[index] = 0; + f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap); + //LOGD_IF(f, "found <%s> instead", scrap); + } + } + if (f == NULL) { + // Try with the OES postfix + ssize_t index = ssize_t(strlen(name)) - 3; + if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) { + strncpy(scrap, name, index); + scrap[index] = 0; + strcat(scrap, "OES"); + f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap); + //LOGD_IF(f, "found <%s> instead", scrap); + } + } if (f == NULL) { - //LOGW("<%s> not found in %s", *api, driver); - f = (void*)0; + //LOGD("%s", name); + f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented; } *curr++ = f; api++; @@ -429,18 +476,19 @@ egl_display_t* get_display(EGLDisplay dpy) return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index]; } +template +static inline NATIVE* egl_to_native_cast(EGL arg) { + return reinterpret_cast(arg); +} + static inline -egl_surface_t* get_surface(EGLSurface surface) -{ - egl_surface_t* s = (egl_surface_t *)surface; - return s; +egl_surface_t* get_surface(EGLSurface surface) { + return egl_to_native_cast(surface); } static inline -egl_context_t* get_context(EGLContext context) -{ - egl_context_t* c = (egl_context_t *)context; - return c; +egl_context_t* get_context(EGLContext context) { + return egl_to_native_cast(context); } static egl_connection_t* validate_display_config( @@ -451,7 +499,7 @@ static egl_connection_t* validate_display_config( if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL); impl = uintptr_t(config)>>24; - if (uint32_t(impl) >= 2) { + if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) { return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL); } index = uintptr_t(config) & 0xFFFFFF; @@ -491,13 +539,8 @@ static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface) return EGL_TRUE; } -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- - -using namespace android; -EGLDisplay eglGetDisplay(NativeDisplayType display) +EGLDisplay egl_init_displays(NativeDisplayType display) { if (sEarlyInitState) { return EGL_NO_DISPLAY; @@ -510,7 +553,7 @@ EGLDisplay eglGetDisplay(NativeDisplayType display) EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU); egl_display_t* d = &gDisplay[index]; - + // dynamically load all our EGL implementations for that display // and call into the real eglGetGisplay() egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE]; @@ -573,6 +616,18 @@ EGLDisplay eglGetDisplay(NativeDisplayType display) return dpy; } + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- + +using namespace android; + +EGLDisplay eglGetDisplay(NativeDisplayType display) +{ + return egl_init_displays(display); +} + // ---------------------------------------------------------------------------- // Initialization // ---------------------------------------------------------------------------- @@ -594,7 +649,7 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) // build our own extension string first, based on the extension we know // and the extension supported by our client implementation dp->extensionsString = strdup(gExtensionString); - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; imajor = -1; cnx->minor = -1; @@ -624,7 +679,7 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) } EGLBoolean res = EGL_FALSE; - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso && cnx->major>=0 && cnx->minor>=0) { EGLint n; @@ -663,7 +718,7 @@ EGLBoolean eglTerminate(EGLDisplay dpy) return EGL_TRUE; EGLBoolean res = EGL_FALSE; - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) { cnx->hooks->egl.eglTerminate(dp->dpys[i]); @@ -706,7 +761,7 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, return EGL_TRUE; } GLint n = 0; - for (int j=0 ; j<2 ; j++) { + for (int j=0 ; jnumConfigs[j] && config_size ; i++) { *configs++ = MAKE_CONFIG(j, i); config_size--; @@ -794,7 +849,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, return res; } - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) { if (cnx->hooks->egl.eglChooseConfig( @@ -1107,7 +1162,7 @@ EGLBoolean eglWaitNative(EGLint engine) EGLint eglGetError(void) { EGLint result = EGL_SUCCESS; - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) @@ -1120,8 +1175,15 @@ EGLint eglGetError(void) return result; } -void (*eglGetProcAddress(const char *procname))() +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) { + // eglGetProcAddress() could be the very first function called + // in which case we must make sure we've initialized ourselves, this + // happens the first time egl_get_display() is called. + + if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY) + return NULL; + __eglMustCastToProperFunctionPointerType addr; addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap)); if (addr) return addr; @@ -1133,7 +1195,7 @@ void (*eglGetProcAddress(const char *procname))() addr = 0; int slot = -1; - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) { if (cnx->hooks->egl.eglGetProcAddress) { @@ -1266,7 +1328,7 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); EGLBoolean res = EGL_TRUE; - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) { if (cnx->hooks->egl.eglSwapInterval) { @@ -1309,7 +1371,7 @@ EGLBoolean eglBindAPI(EGLenum api) { // bind this API on all EGLs EGLBoolean res = EGL_TRUE; - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) { if (cnx->hooks->egl.eglBindAPI) { @@ -1324,7 +1386,7 @@ EGLBoolean eglBindAPI(EGLenum api) EGLenum eglQueryAPI(void) { - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) { if (cnx->hooks->egl.eglQueryAPI) { @@ -1340,7 +1402,7 @@ EGLenum eglQueryAPI(void) EGLBoolean eglReleaseThread(void) { - for (int i=0 ; i<2 ; i++) { + for (int i=0 ; idso) { if (cnx->hooks->egl.eglReleaseThread) { diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp index 3f9fd63405871a5b5ed453385f854d60891e877c..f9dc5f17212e995488ff1ab97a47b93f43266d56 100644 --- a/opengl/libs/EGL/gpu.cpp +++ b/opengl/libs/EGL/gpu.cpp @@ -53,7 +53,7 @@ namespace android { static Mutex gRegionsLock; static request_gpu_t gRegions; static sp gSurfaceManager; -ISurfaceComposer* GLES_localSurfaceManager = 0; +GL_API ISurfaceComposer* GLES_localSurfaceManager = 0; extern egl_connection_t gEGLImpl[2]; diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp index 865cf44362f0a8264919c1740747dd8d26ece908..384b59a3377113713b190eb4b12f0d799be22a8e 100644 --- a/opengl/libs/GLES_CM/gl.cpp +++ b/opengl/libs/GLES_CM/gl.cpp @@ -29,6 +29,7 @@ #include #include "hooks.h" +#include "egl_impl.h" using namespace android; @@ -36,6 +37,17 @@ using namespace android; // extensions for the framework // ---------------------------------------------------------------------------- +extern "C" { +GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, + const GLvoid *ptr, GLsizei count); +GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, + const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +} + void glColorPointerBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr, GLsizei count) { glColorPointer(size, type, stride, ptr); @@ -57,13 +69,6 @@ void glVertexPointerBounds(GLint size, GLenum type, // Actual GL entry-points // ---------------------------------------------------------------------------- -#if GL_LOGGER -# include "gl_logger.h" -# define GL_LOGGER_IMPL(_x) _x -#else -# define GL_LOGGER_IMPL(_x) -#endif - #undef API_ENTRY #undef CALL_GL_API #undef CALL_GL_API_RETURN @@ -96,21 +101,36 @@ void glVertexPointerBounds(GLint size, GLenum type, #define CALL_GL_API(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ - GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); ) \ _c->_api(__VA_ARGS__) #define CALL_GL_API_RETURN(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ - GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); ) \ return _c->_api(__VA_ARGS__) #endif + extern "C" { #include "gl_api.in" +#include "glext_api.in" } #undef API_ENTRY #undef CALL_GL_API #undef CALL_GL_API_RETURN + +/* + * These GL calls are special because they need to call into EGL to retrieve + * some informations before they can execute. + */ + + +void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) +{ +} + +void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) +{ +} + diff --git a/opengl/libs/GLES_CM/gl_api.in b/opengl/libs/GLES_CM/gl_api.in index 9234ef27387fb38f21d37b0ecbe83ecd7c4ef745..5437d47f20ff485635e78a3705aae0555ba53d73 100644 --- a/opengl/libs/GLES_CM/gl_api.in +++ b/opengl/libs/GLES_CM/gl_api.in @@ -1,606 +1,435 @@ -void API_ENTRY(glActiveTexture)(GLenum texture) { - CALL_GL_API(glActiveTexture, texture); -} - void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) { CALL_GL_API(glAlphaFunc, func, ref); } - +void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + CALL_GL_API(glClearColor, red, green, blue, alpha); +} +void API_ENTRY(glClearDepthf)(GLclampf depth) { + CALL_GL_API(glClearDepthf, depth); +} +void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) { + CALL_GL_API(glClipPlanef, plane, equation); +} +void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + CALL_GL_API(glColor4f, red, green, blue, alpha); +} +void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) { + CALL_GL_API(glDepthRangef, zNear, zFar); +} +void API_ENTRY(glFogf)(GLenum pname, GLfloat param) { + CALL_GL_API(glFogf, pname, param); +} +void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) { + CALL_GL_API(glFogfv, pname, params); +} +void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { + CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar); +} +void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) { + CALL_GL_API(glGetClipPlanef, pname, eqn); +} +void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) { + CALL_GL_API(glGetFloatv, pname, params); +} +void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetLightfv, light, pname, params); +} +void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetMaterialfv, face, pname, params); +} +void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetTexEnvfv, env, pname, params); +} +void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetTexParameterfv, target, pname, params); +} +void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) { + CALL_GL_API(glLightModelf, pname, param); +} +void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) { + CALL_GL_API(glLightModelfv, pname, params); +} +void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) { + CALL_GL_API(glLightf, light, pname, param); +} +void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) { + CALL_GL_API(glLightfv, light, pname, params); +} +void API_ENTRY(glLineWidth)(GLfloat width) { + CALL_GL_API(glLineWidth, width); +} +void API_ENTRY(glLoadMatrixf)(const GLfloat *m) { + CALL_GL_API(glLoadMatrixf, m); +} +void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) { + CALL_GL_API(glMaterialf, face, pname, param); +} +void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) { + CALL_GL_API(glMaterialfv, face, pname, params); +} +void API_ENTRY(glMultMatrixf)(const GLfloat *m) { + CALL_GL_API(glMultMatrixf, m); +} +void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { + CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q); +} +void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) { + CALL_GL_API(glNormal3f, nx, ny, nz); +} +void API_ENTRY(glOrthof)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { + CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar); +} +void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) { + CALL_GL_API(glPointParameterf, pname, param); +} +void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) { + CALL_GL_API(glPointParameterfv, pname, params); +} +void API_ENTRY(glPointSize)(GLfloat size) { + CALL_GL_API(glPointSize, size); +} +void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) { + CALL_GL_API(glPolygonOffset, factor, units); +} +void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { + CALL_GL_API(glRotatef, angle, x, y, z); +} +void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) { + CALL_GL_API(glScalef, x, y, z); +} +void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) { + CALL_GL_API(glTexEnvf, target, pname, param); +} +void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) { + CALL_GL_API(glTexEnvfv, target, pname, params); +} +void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { + CALL_GL_API(glTexParameterf, target, pname, param); +} +void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) { + CALL_GL_API(glTexParameterfv, target, pname, params); +} +void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) { + CALL_GL_API(glTranslatef, x, y, z); +} +void API_ENTRY(glActiveTexture)(GLenum texture) { + CALL_GL_API(glActiveTexture, texture); +} void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) { CALL_GL_API(glAlphaFuncx, func, ref); } - +void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { + CALL_GL_API(glBindBuffer, target, buffer); +} void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) { CALL_GL_API(glBindTexture, target, texture); } - void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) { CALL_GL_API(glBlendFunc, sfactor, dfactor); } - +void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) { + CALL_GL_API(glBufferData, target, size, data, usage); +} +void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) { + CALL_GL_API(glBufferSubData, target, offset, size, data); +} void API_ENTRY(glClear)(GLbitfield mask) { CALL_GL_API(glClear, mask); } - -void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - CALL_GL_API(glClearColor, red, green, blue, alpha); -} - void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) { CALL_GL_API(glClearColorx, red, green, blue, alpha); } - -void API_ENTRY(glClearDepthf)(GLclampf depth) { - CALL_GL_API(glClearDepthf, depth); -} - void API_ENTRY(glClearDepthx)(GLclampx depth) { CALL_GL_API(glClearDepthx, depth); } - void API_ENTRY(glClearStencil)(GLint s) { CALL_GL_API(glClearStencil, s); } - void API_ENTRY(glClientActiveTexture)(GLenum texture) { CALL_GL_API(glClientActiveTexture, texture); } - -void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { - CALL_GL_API(glColor4f, red, green, blue, alpha); +void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) { + CALL_GL_API(glClipPlanex, plane, equation); +} +void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { + CALL_GL_API(glColor4ub, red, green, blue, alpha); } - void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { CALL_GL_API(glColor4x, red, green, blue, alpha); } - -void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - CALL_GL_API(glColorMask, r, g, b, a); -} - -void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) -{ - CALL_GL_API(glColorPointer, size, type, stride, ptr); -} - -void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, - GLsizei width, GLsizei height, GLint border, - GLsizei imageSize, const GLvoid *data) { - CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, - width, height, border, imageSize, data); -} - -void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, - const GLvoid *data) { - CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, - width, height, format, imageSize, data); -} - -void API_ENTRY(glCopyTexImage2D)( GLenum target, GLint level, GLenum internalformat, - GLint x, GLint y, GLsizei width, GLsizei height, - GLint border) { - CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, - width, height, border); -} - -void API_ENTRY(glCopyTexSubImage2D)( GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLint x, GLint y, GLsizei width, - GLsizei height) { - CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, - width, height); -} - +void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { + CALL_GL_API(glColorMask, red, green, blue, alpha); +} +void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { + CALL_GL_API(glColorPointer, size, type, stride, pointer); +} +void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) { + CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data); +} +void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) { + CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data); +} +void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { + CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border); +} +void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height); +} void API_ENTRY(glCullFace)(GLenum mode) { CALL_GL_API(glCullFace, mode); } - +void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint *buffers) { + CALL_GL_API(glDeleteBuffers, n, buffers); +} void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) { CALL_GL_API(glDeleteTextures, n, textures); } - void API_ENTRY(glDepthFunc)(GLenum func) { CALL_GL_API(glDepthFunc, func); } - void API_ENTRY(glDepthMask)(GLboolean flag) { CALL_GL_API(glDepthMask, flag); } - -void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) { - CALL_GL_API(glDepthRangef, zNear, zFar); -} - void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) { CALL_GL_API(glDepthRangex, zNear, zFar); } - void API_ENTRY(glDisable)(GLenum cap) { CALL_GL_API(glDisable, cap); } - void API_ENTRY(glDisableClientState)(GLenum array) { CALL_GL_API(glDisableClientState, array); } - void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) { CALL_GL_API(glDrawArrays, mode, first, count); } - -void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, - GLenum type, const GLvoid *indices) { +void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { CALL_GL_API(glDrawElements, mode, count, type, indices); } - void API_ENTRY(glEnable)(GLenum cap) { CALL_GL_API(glEnable, cap); } - void API_ENTRY(glEnableClientState)(GLenum array) { CALL_GL_API(glEnableClientState, array); } - void API_ENTRY(glFinish)(void) { CALL_GL_API(glFinish); } - void API_ENTRY(glFlush)(void) { CALL_GL_API(glFlush); } - -void API_ENTRY(glFogf)(GLenum pname, GLfloat param) { - CALL_GL_API(glFogf, pname, param); -} - -void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glFogfv, pname, params); -} - void API_ENTRY(glFogx)(GLenum pname, GLfixed param) { CALL_GL_API(glFogx, pname, param); } - void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) { CALL_GL_API(glFogxv, pname, params); } - void API_ENTRY(glFrontFace)(GLenum mode) { CALL_GL_API(glFrontFace, mode); } - -void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar) { - CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar); -} - -void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right, - GLfixed bottom, GLfixed top, - GLfixed zNear, GLfixed zFar) { +void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) { CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar); } - +void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) { + CALL_GL_API(glGetBooleanv, pname, params); +} +void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetBufferParameteriv, target, pname, params); +} +void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) { + CALL_GL_API(glGetClipPlanex, pname, eqn); +} +void API_ENTRY(glGenBuffers)(GLsizei n, GLuint *buffers) { + CALL_GL_API(glGenBuffers, n, buffers); +} void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) { CALL_GL_API(glGenTextures, n, textures); } - GLenum API_ENTRY(glGetError)(void) { CALL_GL_API_RETURN(glGetError); } - +void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) { + CALL_GL_API(glGetFixedv, pname, params); +} void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) { CALL_GL_API(glGetIntegerv, pname, params); } - +void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetLightxv, light, pname, params); +} +void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetMaterialxv, face, pname, params); +} +void API_ENTRY(glGetPointerv)(GLenum pname, void **params) { + CALL_GL_API(glGetPointerv, pname, params); +} const GLubyte * API_ENTRY(glGetString)(GLenum name) { CALL_GL_API_RETURN(glGetString, name); } - +void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexEnviv, env, pname, params); +} +void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetTexEnvxv, env, pname, params); +} +void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexParameteriv, target, pname, params); +} +void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetTexParameterxv, target, pname, params); +} void API_ENTRY(glHint)(GLenum target, GLenum mode) { CALL_GL_API(glHint, target, mode); } - -void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) { - CALL_GL_API(glLightModelf, pname, param); +GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { + CALL_GL_API_RETURN(glIsBuffer, buffer); } - -void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glLightModelfv, pname, params); +GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { + CALL_GL_API_RETURN(glIsEnabled, cap); +} +GLboolean API_ENTRY(glIsTexture)(GLuint texture) { + CALL_GL_API_RETURN(glIsTexture, texture); } - void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) { CALL_GL_API(glLightModelx, pname, param); } - void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) { CALL_GL_API(glLightModelxv, pname, params); } - -void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) { - CALL_GL_API(glLightf, light, pname, param); -} - -void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) { - CALL_GL_API(glLightfv, light, pname, params); -} - void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) { CALL_GL_API(glLightx, light, pname, param); } - void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) { CALL_GL_API(glLightxv, light, pname, params); } - -void API_ENTRY(glLineWidth)(GLfloat width) { - CALL_GL_API(glLineWidth, width); -} - void API_ENTRY(glLineWidthx)(GLfixed width) { CALL_GL_API(glLineWidthx, width); } - void API_ENTRY(glLoadIdentity)(void) { CALL_GL_API(glLoadIdentity); } - -void API_ENTRY(glLoadMatrixf)(const GLfloat *m) { - CALL_GL_API(glLoadMatrixf, m); -} - void API_ENTRY(glLoadMatrixx)(const GLfixed *m) { CALL_GL_API(glLoadMatrixx, m); } - void API_ENTRY(glLogicOp)(GLenum opcode) { CALL_GL_API(glLogicOp, opcode); } - -void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) { - CALL_GL_API(glMaterialf, face, pname, param); -} - -void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) { - CALL_GL_API(glMaterialfv, face, pname, params); -} - void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) { CALL_GL_API(glMaterialx, face, pname, param); } - void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) { CALL_GL_API(glMaterialxv, face, pname, params); } - void API_ENTRY(glMatrixMode)(GLenum mode) { CALL_GL_API(glMatrixMode, mode); } - -void API_ENTRY(glMultMatrixf)(const GLfloat *m) { - CALL_GL_API(glMultMatrixf, m); -} - void API_ENTRY(glMultMatrixx)(const GLfixed *m) { CALL_GL_API(glMultMatrixx, m); } - -void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { - CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q); -} - void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) { CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q); } - -void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) { - CALL_GL_API(glNormal3f, nx, ny, nz); -} - void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) { CALL_GL_API(glNormal3x, nx, ny, nz); } - void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) { CALL_GL_API(glNormalPointer, type, stride, pointer); } - -void API_ENTRY(glOrthof)( GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar) { - CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar); -} - -void API_ENTRY(glOrthox)( GLfixed left, GLfixed right, - GLfixed bottom, GLfixed top, - GLfixed zNear, GLfixed zFar) { +void API_ENTRY(glOrthox)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) { CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar); } - void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) { CALL_GL_API(glPixelStorei, pname, param); } - -void API_ENTRY(glPointSize)(GLfloat size) { - CALL_GL_API(glPointSize, size); +void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) { + CALL_GL_API(glPointParameterx, pname, param); +} +void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) { + CALL_GL_API(glPointParameterxv, pname, params); } - void API_ENTRY(glPointSizex)(GLfixed size) { CALL_GL_API(glPointSizex, size); } - -void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) { - CALL_GL_API(glPolygonOffset, factor, units); -} - void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) { CALL_GL_API(glPolygonOffsetx, factor, units); } - void API_ENTRY(glPopMatrix)(void) { CALL_GL_API(glPopMatrix); } - void API_ENTRY(glPushMatrix)(void) { CALL_GL_API(glPushMatrix); } - -void API_ENTRY(glReadPixels)( GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid *pixels) { +void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels); } - -void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { - CALL_GL_API(glRotatef, angle, x, y, z); -} - void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glRotatex, angle, x, y, z); } - void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) { CALL_GL_API(glSampleCoverage, value, invert); } - void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) { CALL_GL_API(glSampleCoveragex, value, invert); } - -void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) { - CALL_GL_API(glScalef, x, y, z); -} - void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glScalex, x, y, z); } - void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glScissor, x, y, width, height); } - void API_ENTRY(glShadeModel)(GLenum mode) { CALL_GL_API(glShadeModel, mode); } - void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) { CALL_GL_API(glStencilFunc, func, ref, mask); } - void API_ENTRY(glStencilMask)(GLuint mask) { CALL_GL_API(glStencilMask, mask); } - void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) { CALL_GL_API(glStencilOp, fail, zfail, zpass); } - -void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type, - GLsizei stride, const GLvoid *pointer) { +void API_ENTRY(glTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { CALL_GL_API(glTexCoordPointer, size, type, stride, pointer); } - -void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) { - CALL_GL_API(glTexEnvf, target, pname, param); -} - -void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) { - CALL_GL_API(glTexEnvfv, target, pname, params); +void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) { + CALL_GL_API(glTexEnvi, target, pname, param); } - void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) { CALL_GL_API(glTexEnvx, target, pname, param); } - +void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) { + CALL_GL_API(glTexEnviv, target, pname, params); +} void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) { CALL_GL_API(glTexEnvxv, target, pname, params); } - -void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLint border, GLenum format, - GLenum type, const GLvoid *pixels) { - CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, - border, format, type, pixels); +void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { + CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels); } - -void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { - CALL_GL_API(glTexParameterf, target, pname, param); +void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { + CALL_GL_API(glTexParameteri, target, pname, param); } - void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) { CALL_GL_API(glTexParameterx, target, pname, param); } - -void API_ENTRY(glTexSubImage2D)( GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid *pixels) { - CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, - width, height, format, type, pixels); +void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { + CALL_GL_API(glTexParameteriv, target, pname, params); } - -void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) { - CALL_GL_API(glTranslatef, x, y, z); +void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) { + CALL_GL_API(glTexParameterxv, target, pname, params); +} +void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) { + CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels); } - void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) { CALL_GL_API(glTranslatex, x, y, z); } - -void API_ENTRY(glVertexPointer)( GLint size, GLenum type, - GLsizei stride, const GLvoid *pointer) { +void API_ENTRY(glVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { CALL_GL_API(glVertexPointer, size, type, stride, pointer); } - void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) { CALL_GL_API(glViewport, x, y, width, height); } - -// ES 1.1 -void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) { - CALL_GL_API(glClipPlanef, plane, equation); -} -void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) { - CALL_GL_API(glClipPlanex, plane, equation); -} -void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { - CALL_GL_API(glBindBuffer, target, buffer); -} -void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { - CALL_GL_API(glBufferData, target, size, data, usage); -} -void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) { - CALL_GL_API(glBufferSubData, target, offset, size, data); -} -void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) { - CALL_GL_API(glDeleteBuffers, n, buffers); -} -void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) { - CALL_GL_API(glGenBuffers, n, buffers); -} -void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) { - CALL_GL_API(glGetBooleanv, pname, params); -} -void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) { - CALL_GL_API(glGetFixedv, pname, params); -} -void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) { - CALL_GL_API(glGetFloatv, pname, params); -} -void API_ENTRY(glGetPointerv)(GLenum pname, void **params) { - CALL_GL_API(glGetPointerv, pname, params); -} -void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) { - CALL_GL_API(glGetBufferParameteriv, target, pname, params); -} -void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) { - CALL_GL_API(glGetClipPlanef, pname, eqn); -} -void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) { - CALL_GL_API(glGetClipPlanex, pname, eqn); -} -void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetLightxv, light, pname, params); -} -void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetLightfv, light, pname, params); -} -void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetMaterialxv, face, pname, params); -} -void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetMaterialfv, face, pname, params); -} -void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetTexEnvfv, env, pname, params); -} -void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) { - CALL_GL_API(glGetTexEnviv, env, pname, params); -} -void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetTexEnvxv, env, pname, params); -} -void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetTexParameterfv, target, pname, params); -} -void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) { - CALL_GL_API(glGetTexParameteriv, target, pname, params); -} -void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetTexParameterxv, target, pname, params); -} -GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { - CALL_GL_API_RETURN(glIsBuffer, buffer); -} -GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { - CALL_GL_API_RETURN(glIsEnabled, cap); -} -GLboolean API_ENTRY(glIsTexture)(GLuint texture) { - CALL_GL_API_RETURN(glIsTexture, texture); -} -void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) { - CALL_GL_API(glPointParameterf, pname, param); -} -void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glPointParameterfv, pname, params); -} -void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) { - CALL_GL_API(glPointParameterx, pname, param); -} -void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) { - CALL_GL_API(glPointParameterxv, pname, params); -} -void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { - CALL_GL_API(glColor4ub, red, green, blue, alpha); -} -void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) { - CALL_GL_API(glTexEnvi, target, pname, param); -} -void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) { - CALL_GL_API(glTexEnviv, target, pname, params); -} - -void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) { - CALL_GL_API(glTexParameterfv, target, pname, params); -} - -void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { - CALL_GL_API(glTexParameteriv, target, pname, params); -} - -void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { - CALL_GL_API(glTexParameteri, target, pname, param); -} -void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) { - CALL_GL_API(glTexParameterxv, target, pname, params); -} void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) { CALL_GL_API(glPointSizePointerOES, type, stride, pointer); } - -// Extensions -void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) { - CALL_GL_API(glDrawTexsOES, x, y, z, w, h); -} -void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) { - CALL_GL_API(glDrawTexiOES, x, y, z, w, h); -} -void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) { - CALL_GL_API(glDrawTexfOES, x, y, z, w, h); -} -void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) { - CALL_GL_API(glDrawTexxOES, x, y, z, w, h); -} -void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) { - CALL_GL_API(glDrawTexsvOES, coords); -} -void API_ENTRY(glDrawTexivOES)(const GLint* coords) { - CALL_GL_API(glDrawTexivOES, coords); -} -void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) { - CALL_GL_API(glDrawTexfvOES, coords); -} -void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) { - CALL_GL_API(glDrawTexxvOES, coords); -} -GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) { - CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent); -} diff --git a/opengl/libs/GLES_CM/gl_logger.cpp b/opengl/libs/GLES_CM/gl_logger.cpp deleted file mode 100644 index 27be5c9bac88f4ba51f8973cca6117253dfe210c..0000000000000000000000000000000000000000 --- a/opengl/libs/GLES_CM/gl_logger.cpp +++ /dev/null @@ -1,1060 +0,0 @@ -/* - ** 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. - */ - -#define LOG_TAG "GLLogger" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "gl_logger.h" - -#undef NELEM -#define NELEM(x) (sizeof(x)/sizeof(*(x))) - -// ---------------------------------------------------------------------------- -namespace android { -// ---------------------------------------------------------------------------- - -template -static int binarySearch(T const sortedArray[], int first, int last, EGLint key) -{ - while (first <= last) { - int mid = (first + last) / 2; - if (key > sortedArray[mid].key) { - first = mid + 1; - } else if (key < sortedArray[mid].key) { - last = mid - 1; - } else { - return mid; - } - } - return -1; -} - -struct pair_t { - const char* name; - int key; -}; - -static const pair_t gEnumMap[] = { - #define GLENUM(NAME, VALUE) { #NAME, VALUE }, - #include "gl_enums.in" - #undef GLENUM -}; - -// ---------------------------------------------------------------------------- - -template -class GLLogValue { -public: - GLLogValue(TYPE value) : mValue(value) { } - const TYPE& getValue() const { return mValue; } - String8 toString() const { - return convertToString(mValue); - } -private: - const TYPE& mValue; - String8 convertToString(unsigned int v) const { - char buf[16]; - snprintf(buf, 16, "%u", v); - return String8(buf); - } - String8 convertToString(unsigned long v) const { - char buf[16]; - snprintf(buf, 16, "%lu", v); - return String8(buf); - } - String8 convertToString(int v) const { - char buf[16]; - snprintf(buf, 16, "%d", v); - return String8(buf); - } - String8 convertToString(long v) const { - char buf[16]; - snprintf(buf, 16, "%ld", v); - return String8(buf); - } - String8 convertToString(float v) const { - char buf[16]; - snprintf(buf, 16, "%f", v); - return String8(buf); - } - String8 convertToString(void const* v) const { - char buf[16]; - snprintf(buf, 16, "%p", v); - return String8(buf); - } -}; - -class GLLogEnum : public GLLogValue { -public: - GLLogEnum(GLenum v) : GLLogValue(v) { } - String8 toString() const { - GLenum v = getValue(); - int i = binarySearch(gEnumMap, 0, NELEM(gEnumMap)-1, v); - if (i >= 0) { - return String8(gEnumMap[i].name); - } else { - char buf[16]; - snprintf(buf, 16, "0x%04x", v); - return String8(buf); - } - } -}; - -class GLLogClearBitfield : public GLLogValue { -public: - GLLogClearBitfield(GLbitfield v) : GLLogValue(v) { } - String8 toString() const { - char buf[16]; - snprintf(buf, 16, "0x%08x", getValue()); - return String8(buf); - } -}; - -class GLLogBool : public GLLogValue { -public: - GLLogBool(GLboolean v) : GLLogValue(v) { } - String8 toString() const { - GLboolean v = getValue(); - if (v == GL_TRUE) return String8("GL_TRUE"); - if (v == GL_FALSE) return String8("GL_FALSE"); - return GLLogValue::toString(); - } -}; - -class GLLogFixed : public GLLogValue { -public: - GLLogFixed(GLfixed v) : GLLogValue(v) { } - String8 toString() const { - char buf[16]; - snprintf(buf, 16, "0x%08x", getValue()); - return String8(buf); - } -}; - - -template -class GLLogBuffer : public GLLogValue { -public: - GLLogBuffer(TYPE* buffer, size_t count = -1) - : GLLogValue(buffer) - { // output buffer - } - GLLogBuffer(TYPE const* buffer, size_t count = -1) - : GLLogValue(const_cast(buffer)) - { // input buffer - } -}; - -class GLLog -{ -public: - GLLog(const char* name) : mNumParams(0) { - mString.append(name); - mString.append("("); - } - - ~GLLog() { - LOGD("%s);", mString.string()); - } - - GLLog& operator << (unsigned char v) { - return *this << GLLogValue(v); - } - GLLog& operator << (short v) { - return *this << GLLogValue(v); - } - GLLog& operator << (unsigned int v) { - return *this << GLLogValue(v); - } - GLLog& operator << (int v) { - return *this << GLLogValue(v); - } - GLLog& operator << (long v) { - return *this << GLLogValue(v); - } - GLLog& operator << (unsigned long v) { - return *this << GLLogValue(v); - } - GLLog& operator << (float v) { - return *this << GLLogValue(v); - } - GLLog& operator << (const void* v) { - return *this << GLLogValue(v); - } - - template - GLLog& operator << (const TYPE& rhs) { - if (mNumParams > 0) - mString.append(", "); - mString.append(rhs.toString()); - mNumParams++; - return *this; - } - - const String8& string() const { return mString; } -private: - GLLog(const GLLog&); - - String8 mString; - int mNumParams; -}; - -#define API_ENTRY(api) log_##api -#define CALL_GL_API(_x, ...) -#define CALL_GL_API_RETURN(_x, ...) return(0); - -void API_ENTRY(glActiveTexture)(GLenum texture) { - CALL_GL_API(glActiveTexture, texture); - GLLog("glActiveTexture") << GLLogEnum(texture); -} - -void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) { - CALL_GL_API(glAlphaFunc, func, ref); - GLLog("glAlphaFunc") << GLLogEnum(func) << ref; -} - -void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) { - CALL_GL_API(glAlphaFuncx, func, ref); - GLLog("glAlphaFuncx") << GLLogEnum(func) << GLLogFixed(ref); -} - -void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) { - CALL_GL_API(glBindTexture, target, texture); - GLLog("glBindTexture") << GLLogEnum(target) << texture; -} - -void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) { - CALL_GL_API(glBlendFunc, sfactor, dfactor); - GLLog("glBlendFunc") << GLLogEnum(sfactor) << GLLogEnum(dfactor); -} - -void API_ENTRY(glClear)(GLbitfield mask) { - CALL_GL_API(glClear, mask); - GLLog("glClear") << GLLogClearBitfield(mask); -} - -void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - CALL_GL_API(glClearColor, red, green, blue, alpha); - GLLog("glClearColor") << red << green << blue << alpha; -} - -void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) { - CALL_GL_API(glClearColorx, red, green, blue, alpha); - GLLog("glClearColorx") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha); -} - -void API_ENTRY(glClearDepthf)(GLclampf depth) { - CALL_GL_API(glClearDepthf, depth); - GLLog("glClearDepthf") << depth; -} - -void API_ENTRY(glClearDepthx)(GLclampx depth) { - CALL_GL_API(glClearDepthx, depth); - GLLog("glClearDepthx") << GLLogFixed(depth); -} - -void API_ENTRY(glClearStencil)(GLint s) { - CALL_GL_API(glClearStencil, s); - GLLog("glClearStencil") << s; -} - -void API_ENTRY(glClientActiveTexture)(GLenum texture) { - CALL_GL_API(glClientActiveTexture, texture); - GLLog("glClientActiveTexture") << GLLogEnum(texture); -} - -void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { - CALL_GL_API(glColor4f, red, green, blue, alpha); - GLLog("glColor4f") << red << green << blue << alpha; -} - -void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { - CALL_GL_API(glColor4x, red, green, blue, alpha); - GLLog("glColor4x") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha); -} - -void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - CALL_GL_API(glColorMask, r, g, b, a); - GLLog("glColorMask") << GLLogBool(r) << GLLogBool(g) << GLLogBool(b) << GLLogBool(a); -} - -void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) -{ - CALL_GL_API(glColorPointer, size, type, stride, ptr); - GLLog("glColorPointer") << size << GLLogEnum(type) << stride << ptr; -} - -void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, - GLsizei width, GLsizei height, GLint border, - GLsizei imageSize, const GLvoid *data) { - CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, - width, height, border, imageSize, data); - GLLog("glCompressedTexImage2D") - << GLLogEnum(target) << level << GLLogEnum(internalformat) - << width << height << border << imageSize << data; -} - -void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, - const GLvoid *data) { - CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, - width, height, format, imageSize, data); - GLLog("glCompressedTexSubImage2D") - << GLLogEnum(target) << level << xoffset << yoffset - << width << height << GLLogEnum(format) << imageSize << data; -} - -void API_ENTRY(glCopyTexImage2D)( GLenum target, GLint level, GLenum internalformat, - GLint x, GLint y, GLsizei width, GLsizei height, - GLint border) { - CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, - width, height, border); - GLLog("glCopyTexImage2D") - << GLLogEnum(target) << level << GLLogEnum(internalformat) - << x << y << width << height << border; -} - -void API_ENTRY(glCopyTexSubImage2D)( GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLint x, GLint y, GLsizei width, - GLsizei height) { - CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, - width, height); - GLLog("glCopyTexSubImage2D") - << GLLogEnum(target) << level << xoffset << yoffset - << x << y << width << height; -} - -void API_ENTRY(glCullFace)(GLenum mode) { - CALL_GL_API(glCullFace, mode); - GLLog("glCullFace") << GLLogEnum(mode); -} - -void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) { - CALL_GL_API(glDeleteTextures, n, textures); - GLLog("glDeleteTextures") << n << GLLogBuffer(textures, n); -} - -void API_ENTRY(glDepthFunc)(GLenum func) { - CALL_GL_API(glDepthFunc, func); - GLLog("glDepthFunc") << GLLogEnum(func); -} - -void API_ENTRY(glDepthMask)(GLboolean flag) { - CALL_GL_API(glDepthMask, flag); - GLLog("glDepthMask") << GLLogBool(flag); -} - -void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) { - CALL_GL_API(glDepthRangef, zNear, zFar); - GLLog("glDepthRangef") << zNear << zFar; -} - -void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) { - CALL_GL_API(glDepthRangex, zNear, zFar); - GLLog("glDepthRangex") << GLLogFixed(zNear) << GLLogFixed(zFar); -} - -void API_ENTRY(glDisable)(GLenum cap) { - CALL_GL_API(glDisable, cap); - GLLog("glDisable") << GLLogEnum(cap); -} - -void API_ENTRY(glDisableClientState)(GLenum array) { - CALL_GL_API(glDisableClientState, array); - GLLog("glDisableClientState") << GLLogEnum(array); -} - -void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) { - CALL_GL_API(glDrawArrays, mode, first, count); - GLLog("glDrawArrays") << GLLogEnum(mode) << first << count; -} - -void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, - GLenum type, const GLvoid *indices) { - CALL_GL_API(glDrawElements, mode, count, type, indices); - GLLog log("glDrawElements"); - log << GLLogEnum(mode) << count << GLLogEnum(type); - if (type == GL_UNSIGNED_BYTE) { - log << GLLogBuffer(static_cast(indices), count); - } else { - log << GLLogBuffer(static_cast(indices), count); - } - log; -} - -void API_ENTRY(glEnable)(GLenum cap) { - CALL_GL_API(glEnable, cap); - GLLog("glEnable") << GLLogEnum(cap); -} - -void API_ENTRY(glEnableClientState)(GLenum array) { - CALL_GL_API(glEnableClientState, array); - GLLog("glEnableClientState") << GLLogEnum(array); -} - -void API_ENTRY(glFinish)(void) { - CALL_GL_API(glFinish); - GLLog("glFinish"); -} - -void API_ENTRY(glFlush)(void) { - CALL_GL_API(glFlush); - GLLog("glFlush"); -} - -void API_ENTRY(glFogf)(GLenum pname, GLfloat param) { - CALL_GL_API(glFogf, pname, param); - GLLog("glFogf") << GLLogEnum(pname) << param; -} - -void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glFogfv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glFogfv") << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glFogx)(GLenum pname, GLfixed param) { - CALL_GL_API(glFogx, pname, param); - GLLog("glFogx") << GLLogEnum(pname) << GLLogFixed(param); -} - -void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) { - CALL_GL_API(glFogxv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glFogfx") << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glFrontFace)(GLenum mode) { - CALL_GL_API(glFrontFace, mode); - GLLog("glFrontFace") << GLLogEnum(mode); - } - -void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar) { - CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar); - GLLog("glFrustumf") << left << right << bottom << top << zNear << zFar; -} - -void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right, - GLfixed bottom, GLfixed top, - GLfixed zNear, GLfixed zFar) { - CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar); - GLLog("glFrustumx") - << GLLogFixed(left) << GLLogFixed(right) - << GLLogFixed(bottom) << GLLogFixed(top) - << GLLogFixed(zNear) << GLLogFixed(zFar); -} - -void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) { - CALL_GL_API(glGenTextures, n, textures); - GLLog("glGenTextures") << n << GLLogBuffer(textures, n); -} - -GLenum API_ENTRY(glGetError)(void) { - GLLog("glGetError"); - CALL_GL_API_RETURN(glGetError); -} - -void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) { - CALL_GL_API(glGetIntegerv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetIntegerv") << GLLogEnum(pname) << GLLogBuffer(params); -} - -const GLubyte * API_ENTRY(glGetString)(GLenum name) { - GLLog("glGetString") << GLLogEnum(name); - CALL_GL_API_RETURN(glGetString, name); -} - -void API_ENTRY(glHint)(GLenum target, GLenum mode) { - CALL_GL_API(glHint, target, mode); - GLLog("GLenum") << GLLogEnum(target) << GLLogEnum(mode); -} - -void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) { - CALL_GL_API(glLightModelf, pname, param); - GLLog("glLightModelf") << GLLogEnum(pname) << param; -} - -void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glLightModelfv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glLightModelfv") << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) { - CALL_GL_API(glLightModelx, pname, param); - GLLog("glLightModelx") << GLLogEnum(pname) << GLLogFixed(param); -} - -void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) { - CALL_GL_API(glLightModelxv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glLightModelxv") << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) { - CALL_GL_API(glLightf, light, pname, param); - GLLog("glLightf") << GLLogEnum(light) << GLLogEnum(pname) << param; -} - -void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) { - CALL_GL_API(glLightfv, light, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) { - CALL_GL_API(glLightx, light, pname, param); - GLLog("glLightx") << GLLogEnum(light) << GLLogEnum(pname) << GLLogFixed(param); -} - -void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) { - CALL_GL_API(glLightxv, light, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glLineWidth)(GLfloat width) { - CALL_GL_API(glLineWidth, width); - GLLog("glLineWidth") << width; -} - -void API_ENTRY(glLineWidthx)(GLfixed width) { - CALL_GL_API(glLineWidthx, width); - GLLog("glLineWidth") << GLLogFixed(width); -} - -void API_ENTRY(glLoadIdentity)(void) { - CALL_GL_API(glLoadIdentity); - GLLog("glLoadIdentity"); -} - -void API_ENTRY(glLoadMatrixf)(const GLfloat *m) { - CALL_GL_API(glLoadMatrixf, m); - GLLog("glLoadMatrixf") << GLLogBuffer(m, 16); -} - -void API_ENTRY(glLoadMatrixx)(const GLfixed *m) { - CALL_GL_API(glLoadMatrixx, m); - GLLog("glLoadMatrixx") << GLLogBuffer(m, 16); -} - -void API_ENTRY(glLogicOp)(GLenum opcode) { - CALL_GL_API(glLogicOp, opcode); - GLLog("glLogicOp") << GLLogEnum(opcode); -} - -void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) { - CALL_GL_API(glMaterialf, face, pname, param); - GLLog("glMaterialf") << GLLogEnum(face) << GLLogEnum(pname) << param; -} - -void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) { - CALL_GL_API(glMaterialfv, face, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) { - CALL_GL_API(glMaterialx, face, pname, param); - GLLog("glMaterialx") << GLLogEnum(face) << GLLogEnum(pname) << GLLogFixed(param); -} - -void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) { - CALL_GL_API(glMaterialxv, face, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glMatrixMode)(GLenum mode) { - CALL_GL_API(glMatrixMode, mode); - GLLog("glMatrixMode") << GLLogEnum(mode); -} - -void API_ENTRY(glMultMatrixf)(const GLfloat *m) { - CALL_GL_API(glMultMatrixf, m); - GLLog("glMultMatrixf") << GLLogBuffer(m, 16); -} - -void API_ENTRY(glMultMatrixx)(const GLfixed *m) { - CALL_GL_API(glMultMatrixx, m); - GLLog("glMultMatrixx") << GLLogBuffer(m, 16); -} - -void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { - CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q); - GLLog("glMultiTexCoord4f") << GLLogEnum(target) << s << t << r << q; -} - -void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) { - CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q); - GLLog("glMultiTexCoord4x") << GLLogEnum(target) - << GLLogFixed(s) << GLLogFixed(t) << GLLogFixed(r) << GLLogFixed(q); -} - -void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) { - CALL_GL_API(glNormal3f, nx, ny, nz); - GLLog("glNormal3f") << nx << ny << nz; -} - -void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) { - CALL_GL_API(glNormal3x, nx, ny, nz); - GLLog("glNormal3x") << GLLogFixed(nx) << GLLogFixed(ny) << GLLogFixed(nz); -} - -void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) { - CALL_GL_API(glNormalPointer, type, stride, pointer); - GLLog("glNormalPointer") << GLLogEnum(type) << stride << pointer; -} - -void API_ENTRY(glOrthof)( GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar) { - CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar); - GLLog("glOrthof") << left << right << bottom << top << zNear << zFar; -} - -void API_ENTRY(glOrthox)( GLfixed left, GLfixed right, - GLfixed bottom, GLfixed top, - GLfixed zNear, GLfixed zFar) { - CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar); - GLLog("glOrthox") << GLLogFixed(left) << GLLogFixed(right) - << GLLogFixed(bottom) << GLLogFixed(top) - << GLLogFixed(zNear) << GLLogFixed(zFar); -} - -void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) { - CALL_GL_API(glPixelStorei, pname, param); - GLLog("glPixelStorei") << GLLogEnum(pname) << param; -} - -void API_ENTRY(glPointSize)(GLfloat size) { - CALL_GL_API(glPointSize, size); - GLLog("glPointSize") << size; -} - -void API_ENTRY(glPointSizex)(GLfixed size) { - CALL_GL_API(glPointSizex, size); - GLLog("glPointSizex") << GLLogFixed(size); -} - -void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) { - CALL_GL_API(glPolygonOffset, factor, units); - GLLog("glPolygonOffset") << factor << units; -} - -void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) { - CALL_GL_API(glPolygonOffsetx, factor, units); - GLLog("glPolygonOffsetx") << GLLogFixed(factor) << GLLogFixed(units); -} - -void API_ENTRY(glPopMatrix)(void) { - CALL_GL_API(glPopMatrix); - GLLog("glPopMatrix"); -} - -void API_ENTRY(glPushMatrix)(void) { - CALL_GL_API(glPushMatrix); - GLLog("glPushMatrix"); -} - -void API_ENTRY(glReadPixels)( GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid *pixels) { - CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels); - // XXX: we need to compute the size of this buffer - GLLog("glReadPixels") << x << y << width << height << GLLogEnum(format) << GLLogEnum(type) - << GLLogBuffer(static_cast(pixels)); -} - -void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { - CALL_GL_API(glRotatef, angle, x, y, z); - GLLog("glRotatef") << angle << x << y << z; -} - -void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { - CALL_GL_API(glRotatex, angle, x, y, z); - GLLog("glRotatex") << GLLogFixed(angle) << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z); -} - -void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) { - CALL_GL_API(glSampleCoverage, value, invert); - GLLog("glSampleCoverage") << value << GLLogBool(invert); -} - -void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) { - CALL_GL_API(glSampleCoveragex, value, invert); - GLLog("glSampleCoveragex") << GLLogFixed(value) << GLLogBool(invert); -} - -void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) { - CALL_GL_API(glScalef, x, y, z); - GLLog("glScalef") << x << y << z; -} - -void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) { - CALL_GL_API(glScalex, x, y, z); - GLLog("glScalex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z); -} - -void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) { - CALL_GL_API(glScissor, x, y, width, height); - GLLog("glScissor") << x << y << width << height; -} - -void API_ENTRY(glShadeModel)(GLenum mode) { - CALL_GL_API(glShadeModel, mode); - GLLog("glShadeModel") << GLLogEnum(mode); -} - -void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) { - CALL_GL_API(glStencilFunc, func, ref, mask); - GLLog("glStencilFunc") << GLLogEnum(func) << ref << mask; -} - -void API_ENTRY(glStencilMask)(GLuint mask) { - CALL_GL_API(glStencilMask, mask); - GLLog("glStencilMask") << mask; -} - -void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) { - CALL_GL_API(glStencilOp, fail, zfail, zpass); - GLLog("glStencilOp") << GLLogEnum(fail) << GLLogEnum(zfail) << GLLogEnum(zpass); -} - -void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type, - GLsizei stride, const GLvoid *pointer) { - CALL_GL_API(glTexCoordPointer, size, type, stride, pointer); - GLLog("glTexCoordPointer") << size << GLLogEnum(type) << stride << pointer; -} - -void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) { - CALL_GL_API(glTexEnvf, target, pname, param); - GLLog("glTexEnvf") << GLLogEnum(target) << GLLogEnum(pname) << param; -} - -void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) { - CALL_GL_API(glTexEnvfv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) { - CALL_GL_API(glTexEnvx, target, pname, param); - GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param); -} - -void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) { - CALL_GL_API(glTexEnvxv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glTexEnvxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLint border, GLenum format, - GLenum type, const GLvoid *pixels) { - CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, - border, format, type, pixels); - GLLog("glTexImage2D") << GLLogEnum(target) << level << GLLogEnum(internalformat) - << width << height << border << GLLogEnum(format) << GLLogEnum(type) - << GLLogBuffer( static_cast(pixels)); -} - -void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { - CALL_GL_API(glTexParameterf, target, pname, param); - GLLog("glTexParameterf") << GLLogEnum(target) << GLLogEnum(pname) << param; -} - -void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) { - CALL_GL_API(glTexParameterx, target, pname, param); - GLLog("glTexParameterx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param); -} - -void API_ENTRY(glTexSubImage2D)( GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid *pixels) { - CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, - width, height, format, type, pixels); - GLLog("glTexSubImage2D") << GLLogEnum(target) << level << xoffset << yoffset - << width << height << GLLogEnum(format) << GLLogEnum(type) - << GLLogBuffer( static_cast(pixels)); -} - -void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) { - CALL_GL_API(glTranslatef, x, y, z); - GLLog("glTranslatef") << x << y << z; -} - -void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) { - CALL_GL_API(glTranslatex, x, y, z); - GLLog("glTranslatex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z); -} - -void API_ENTRY(glVertexPointer)( GLint size, GLenum type, - GLsizei stride, const GLvoid *pointer) { - CALL_GL_API(glVertexPointer, size, type, stride, pointer); - GLLog("glVertexPointer") << size << GLLogEnum(type) << stride << pointer; -} - -void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) { - CALL_GL_API(glViewport, x, y, width, height); - GLLog("glViewport") << x << y << width << height; -} - -// ES 1.1 -void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) { - CALL_GL_API(glClipPlanef, plane, equation); - GLLog("glClipPlanef") << GLLogEnum(plane) << GLLogBuffer(equation, 4); -} -void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) { - CALL_GL_API(glClipPlanex, plane, equation); - GLLog("glClipPlanex") << GLLogEnum(plane) << GLLogBuffer(equation, 4); -} -void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { - CALL_GL_API(glBindBuffer, target, buffer); - GLLog("glBindBuffer") << GLLogEnum(target) << buffer; -} -void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { - CALL_GL_API(glBufferData, target, size, data, usage); - GLLog("glBufferData") << GLLogEnum(target) << size - << GLLogBuffer(static_cast(data), size); -} -void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) { - CALL_GL_API(glBufferSubData, target, offset, size, data); - GLLog("glBufferSubData") << GLLogEnum(target) << offset << size - << GLLogBuffer(static_cast(data), size); -} -void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) { - CALL_GL_API(glDeleteBuffers, n, buffers); - GLLog("glDeleteBuffers") << n << GLLogBuffer(buffers, n); -} -void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) { - CALL_GL_API(glGenBuffers, n, buffers); - GLLog("glGenBuffers") << n << GLLogBuffer(buffers, n); -} -void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) { - CALL_GL_API(glGetBooleanv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetBooleanv") << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) { - CALL_GL_API(glGetFixedv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetFixedv") << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) { - CALL_GL_API(glGetFloatv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetFloatv") << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetPointerv)(GLenum pname, void **params) { - CALL_GL_API(glGetPointerv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetPointerv") << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) { - // XXX: we need to compute the size of this buffer - CALL_GL_API(glGetBufferParameteriv, target, pname, params); - GLLog("glGetBufferParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) { - CALL_GL_API(glGetClipPlanef, pname, eqn); - GLLog("glGetClipPlanef") << GLLogEnum(pname) << GLLogBuffer(eqn, 4); -} -void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) { - CALL_GL_API(glGetClipPlanex, pname, eqn); - GLLog("glGetClipPlanex") << GLLogEnum(pname) << GLLogBuffer(eqn, 4); -} -void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetLightxv, light, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetLightfv, light, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetMaterialxv, face, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetMaterialfv, face, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetTexEnvfv, env, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetTexEnvfv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) { - CALL_GL_API(glGetTexEnviv, env, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetTexEnviv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetTexEnvxv, env, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetTexEnvxv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) { - CALL_GL_API(glGetTexParameterfv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) { - CALL_GL_API(glGetTexParameteriv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) { - CALL_GL_API(glGetTexParameterxv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glGetTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} -GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { - GLLog("glIsBuffer") << buffer; - CALL_GL_API_RETURN(glIsBuffer, buffer); -} -GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { - GLLog("glIsEnabled") << GLLogEnum(cap); - CALL_GL_API_RETURN(glIsEnabled, cap); -} -GLboolean API_ENTRY(glIsTexture)(GLuint texture) { - GLLog("glIsTexture") << texture; - CALL_GL_API_RETURN(glIsTexture, texture); -} -void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) { - CALL_GL_API(glPointParameterf, pname, param); - GLLog("glPointParameterf") << GLLogEnum(pname) << param; -} -void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glPointParameterfv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glPointParameterfv") << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) { - CALL_GL_API(glPointParameterx, pname, param); - GLLog("glPointParameterx") << GLLogEnum(pname) << GLLogFixed(param); -} -void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) { - CALL_GL_API(glPointParameterxv, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glPointParameterxv") << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { - CALL_GL_API(glColor4ub, red, green, blue, alpha); - GLLog("glColor4ub") << red << green << blue << alpha; -} -void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) { - CALL_GL_API(glTexEnvi, target, pname, param); - GLLog("glTexEnvi") << GLLogEnum(target) << GLLogEnum(pname) << param; -} -void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) { - CALL_GL_API(glTexEnviv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glTexEnviv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) { - CALL_GL_API(glTexParameterfv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { - CALL_GL_API(glTexParameteriv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} - -void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { - CALL_GL_API(glTexParameteri, target, pname, param); - GLLog("glTexParameteri") << GLLogEnum(target) << GLLogEnum(pname) << param; -} -void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) { - CALL_GL_API(glTexParameterxv, target, pname, params); - // XXX: we need to compute the size of this buffer - GLLog("glTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer(params); -} -void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) { - CALL_GL_API(glPointSizePointerOES, type, stride, pointer); - GLLog("glPointSizePointerOES") << GLLogEnum(type) << stride << pointer; -} - -// Extensions -void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) { - CALL_GL_API(glDrawTexsOES, x, y, z, w, h); - GLLog("glDrawTexsOES") << x << y << z << w << h; -} -void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) { - CALL_GL_API(glDrawTexiOES, x, y, z, w, h); - GLLog("glDrawTexiOES") << x << y << z << w << h; -} -void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) { - CALL_GL_API(glDrawTexfOES, x, y, z, w, h); - GLLog("glDrawTexfOES") << x << y << z << w << h; -} -void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) { - CALL_GL_API(glDrawTexxOES, x, y, z, w, h); - GLLog("glDrawTexfOES") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z) << GLLogFixed(w) << GLLogFixed(h); -} -void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) { - CALL_GL_API(glDrawTexsvOES, coords); - GLLog("glDrawTexsvOES") << GLLogBuffer(coords, 5); -} -void API_ENTRY(glDrawTexivOES)(const GLint* coords) { - CALL_GL_API(glDrawTexivOES, coords); - GLLog("glDrawTexivOES") << GLLogBuffer(coords, 5); -} -void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) { - CALL_GL_API(glDrawTexfvOES, coords); - GLLog("glDrawTexfvOES") << GLLogBuffer(coords, 5); -} -void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) { - CALL_GL_API(glDrawTexxvOES, coords); - GLLog("glDrawTexxvOES") << GLLogBuffer(coords, 5); -} -GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) { - GLLog("glQueryMatrixxOES") << GLLogBuffer(mantissa, 16) << GLLogBuffer(exponent, 16); - CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent); -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in new file mode 100644 index 0000000000000000000000000000000000000000..2c8648e259ba28b731dd845860584ee823281418 --- /dev/null +++ b/opengl/libs/GLES_CM/glext_api.in @@ -0,0 +1,270 @@ +void API_ENTRY(glBlendEquationSeparateOES)(GLenum modeRGB, GLenum modeAlpha) { + CALL_GL_API(glBlendEquationSeparateOES, modeRGB, modeAlpha); +} +void API_ENTRY(glBlendFuncSeparateOES)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { + CALL_GL_API(glBlendFuncSeparateOES, srcRGB, dstRGB, srcAlpha, dstAlpha); +} +void API_ENTRY(glBlendEquationOES)(GLenum mode) { + CALL_GL_API(glBlendEquationOES, mode); +} +void API_ENTRY(glDrawTexsOES)(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) { + CALL_GL_API(glDrawTexsOES, x, y, z, width, height); +} +void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint width, GLint height) { + CALL_GL_API(glDrawTexiOES, x, y, z, width, height); +} +void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) { + CALL_GL_API(glDrawTexxOES, x, y, z, width, height); +} +void API_ENTRY(glDrawTexsvOES)(const GLshort *coords) { + CALL_GL_API(glDrawTexsvOES, coords); +} +void API_ENTRY(glDrawTexivOES)(const GLint *coords) { + CALL_GL_API(glDrawTexivOES, coords); +} +void API_ENTRY(glDrawTexxvOES)(const GLfixed *coords) { + CALL_GL_API(glDrawTexxvOES, coords); +} +void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) { + CALL_GL_API(glDrawTexfOES, x, y, z, width, height); +} +void API_ENTRY(glDrawTexfvOES)(const GLfloat *coords) { + CALL_GL_API(glDrawTexfvOES, coords); +} +void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { + CALL_GL_API(glEGLImageTargetTexture2DOES, target, image); +} +void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { + CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image); +} +void API_ENTRY(glAlphaFuncxOES)(GLenum func, GLclampx ref) { + CALL_GL_API(glAlphaFuncxOES, func, ref); +} +void API_ENTRY(glClearColorxOES)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) { + CALL_GL_API(glClearColorxOES, red, green, blue, alpha); +} +void API_ENTRY(glClearDepthxOES)(GLclampx depth) { + CALL_GL_API(glClearDepthxOES, depth); +} +void API_ENTRY(glClipPlanexOES)(GLenum plane, const GLfixed *equation) { + CALL_GL_API(glClipPlanexOES, plane, equation); +} +void API_ENTRY(glColor4xOES)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { + CALL_GL_API(glColor4xOES, red, green, blue, alpha); +} +void API_ENTRY(glDepthRangexOES)(GLclampx zNear, GLclampx zFar) { + CALL_GL_API(glDepthRangexOES, zNear, zFar); +} +void API_ENTRY(glFogxOES)(GLenum pname, GLfixed param) { + CALL_GL_API(glFogxOES, pname, param); +} +void API_ENTRY(glFogxvOES)(GLenum pname, const GLfixed *params) { + CALL_GL_API(glFogxvOES, pname, params); +} +void API_ENTRY(glFrustumxOES)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) { + CALL_GL_API(glFrustumxOES, left, right, bottom, top, zNear, zFar); +} +void API_ENTRY(glGetClipPlanexOES)(GLenum pname, GLfixed eqn[4]) { + CALL_GL_API(glGetClipPlanexOES, pname, eqn); +} +void API_ENTRY(glGetFixedvOES)(GLenum pname, GLfixed *params) { + CALL_GL_API(glGetFixedvOES, pname, params); +} +void API_ENTRY(glGetLightxvOES)(GLenum light, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetLightxvOES, light, pname, params); +} +void API_ENTRY(glGetMaterialxvOES)(GLenum face, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetMaterialxvOES, face, pname, params); +} +void API_ENTRY(glGetTexEnvxvOES)(GLenum env, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetTexEnvxvOES, env, pname, params); +} +void API_ENTRY(glGetTexParameterxvOES)(GLenum target, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetTexParameterxvOES, target, pname, params); +} +void API_ENTRY(glLightModelxOES)(GLenum pname, GLfixed param) { + CALL_GL_API(glLightModelxOES, pname, param); +} +void API_ENTRY(glLightModelxvOES)(GLenum pname, const GLfixed *params) { + CALL_GL_API(glLightModelxvOES, pname, params); +} +void API_ENTRY(glLightxOES)(GLenum light, GLenum pname, GLfixed param) { + CALL_GL_API(glLightxOES, light, pname, param); +} +void API_ENTRY(glLightxvOES)(GLenum light, GLenum pname, const GLfixed *params) { + CALL_GL_API(glLightxvOES, light, pname, params); +} +void API_ENTRY(glLineWidthxOES)(GLfixed width) { + CALL_GL_API(glLineWidthxOES, width); +} +void API_ENTRY(glLoadMatrixxOES)(const GLfixed *m) { + CALL_GL_API(glLoadMatrixxOES, m); +} +void API_ENTRY(glMaterialxOES)(GLenum face, GLenum pname, GLfixed param) { + CALL_GL_API(glMaterialxOES, face, pname, param); +} +void API_ENTRY(glMaterialxvOES)(GLenum face, GLenum pname, const GLfixed *params) { + CALL_GL_API(glMaterialxvOES, face, pname, params); +} +void API_ENTRY(glMultMatrixxOES)(const GLfixed *m) { + CALL_GL_API(glMultMatrixxOES, m); +} +void API_ENTRY(glMultiTexCoord4xOES)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) { + CALL_GL_API(glMultiTexCoord4xOES, target, s, t, r, q); +} +void API_ENTRY(glNormal3xOES)(GLfixed nx, GLfixed ny, GLfixed nz) { + CALL_GL_API(glNormal3xOES, nx, ny, nz); +} +void API_ENTRY(glOrthoxOES)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) { + CALL_GL_API(glOrthoxOES, left, right, bottom, top, zNear, zFar); +} +void API_ENTRY(glPointParameterxOES)(GLenum pname, GLfixed param) { + CALL_GL_API(glPointParameterxOES, pname, param); +} +void API_ENTRY(glPointParameterxvOES)(GLenum pname, const GLfixed *params) { + CALL_GL_API(glPointParameterxvOES, pname, params); +} +void API_ENTRY(glPointSizexOES)(GLfixed size) { + CALL_GL_API(glPointSizexOES, size); +} +void API_ENTRY(glPolygonOffsetxOES)(GLfixed factor, GLfixed units) { + CALL_GL_API(glPolygonOffsetxOES, factor, units); +} +void API_ENTRY(glRotatexOES)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { + CALL_GL_API(glRotatexOES, angle, x, y, z); +} +void API_ENTRY(glSampleCoveragexOES)(GLclampx value, GLboolean invert) { + CALL_GL_API(glSampleCoveragexOES, value, invert); +} +void API_ENTRY(glScalexOES)(GLfixed x, GLfixed y, GLfixed z) { + CALL_GL_API(glScalexOES, x, y, z); +} +void API_ENTRY(glTexEnvxOES)(GLenum target, GLenum pname, GLfixed param) { + CALL_GL_API(glTexEnvxOES, target, pname, param); +} +void API_ENTRY(glTexEnvxvOES)(GLenum target, GLenum pname, const GLfixed *params) { + CALL_GL_API(glTexEnvxvOES, target, pname, params); +} +void API_ENTRY(glTexParameterxOES)(GLenum target, GLenum pname, GLfixed param) { + CALL_GL_API(glTexParameterxOES, target, pname, param); +} +void API_ENTRY(glTexParameterxvOES)(GLenum target, GLenum pname, const GLfixed *params) { + CALL_GL_API(glTexParameterxvOES, target, pname, params); +} +void API_ENTRY(glTranslatexOES)(GLfixed x, GLfixed y, GLfixed z) { + CALL_GL_API(glTranslatexOES, x, y, z); +} +GLboolean API_ENTRY(glIsRenderbufferOES)(GLuint renderbuffer) { + CALL_GL_API_RETURN(glIsRenderbufferOES, renderbuffer); +} +void API_ENTRY(glBindRenderbufferOES)(GLenum target, GLuint renderbuffer) { + CALL_GL_API(glBindRenderbufferOES, target, renderbuffer); +} +void API_ENTRY(glDeleteRenderbuffersOES)(GLsizei n, const GLuint* renderbuffers) { + CALL_GL_API(glDeleteRenderbuffersOES, n, renderbuffers); +} +void API_ENTRY(glGenRenderbuffersOES)(GLsizei n, GLuint* renderbuffers) { + CALL_GL_API(glGenRenderbuffersOES, n, renderbuffers); +} +void API_ENTRY(glRenderbufferStorageOES)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glRenderbufferStorageOES, target, internalformat, width, height); +} +void API_ENTRY(glGetRenderbufferParameterivOES)(GLenum target, GLenum pname, GLint* params) { + CALL_GL_API(glGetRenderbufferParameterivOES, target, pname, params); +} +GLboolean API_ENTRY(glIsFramebufferOES)(GLuint framebuffer) { + CALL_GL_API_RETURN(glIsFramebufferOES, framebuffer); +} +void API_ENTRY(glBindFramebufferOES)(GLenum target, GLuint framebuffer) { + CALL_GL_API(glBindFramebufferOES, target, framebuffer); +} +void API_ENTRY(glDeleteFramebuffersOES)(GLsizei n, const GLuint* framebuffers) { + CALL_GL_API(glDeleteFramebuffersOES, n, framebuffers); +} +void API_ENTRY(glGenFramebuffersOES)(GLsizei n, GLuint* framebuffers) { + CALL_GL_API(glGenFramebuffersOES, n, framebuffers); +} +GLenum API_ENTRY(glCheckFramebufferStatusOES)(GLenum target) { + CALL_GL_API_RETURN(glCheckFramebufferStatusOES, target); +} +void API_ENTRY(glFramebufferRenderbufferOES)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { + CALL_GL_API(glFramebufferRenderbufferOES, target, attachment, renderbuffertarget, renderbuffer); +} +void API_ENTRY(glFramebufferTexture2DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { + CALL_GL_API(glFramebufferTexture2DOES, target, attachment, textarget, texture, level); +} +void API_ENTRY(glGetFramebufferAttachmentParameterivOES)(GLenum target, GLenum attachment, GLenum pname, GLint* params) { + CALL_GL_API(glGetFramebufferAttachmentParameterivOES, target, attachment, pname, params); +} +void API_ENTRY(glGenerateMipmapOES)(GLenum target) { + CALL_GL_API(glGenerateMipmapOES, target); +} +void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) { + CALL_GL_API_RETURN(glMapBufferOES, target, access); +} +GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) { + CALL_GL_API_RETURN(glUnmapBufferOES, target); +} +void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void** params) { + CALL_GL_API(glGetBufferPointervOES, target, pname, params); +} +void API_ENTRY(glCurrentPaletteMatrixOES)(GLuint matrixpaletteindex) { + CALL_GL_API(glCurrentPaletteMatrixOES, matrixpaletteindex); +} +void API_ENTRY(glLoadPaletteFromModelViewMatrixOES)(void) { + CALL_GL_API(glLoadPaletteFromModelViewMatrixOES); +} +void API_ENTRY(glMatrixIndexPointerOES)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { + CALL_GL_API(glMatrixIndexPointerOES, size, type, stride, pointer); +} +void API_ENTRY(glWeightPointerOES)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { + CALL_GL_API(glWeightPointerOES, size, type, stride, pointer); +} +GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed mantissa[16], GLint exponent[16]) { + CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent); +} +void API_ENTRY(glDepthRangefOES)(GLclampf zNear, GLclampf zFar) { + CALL_GL_API(glDepthRangefOES, zNear, zFar); +} +void API_ENTRY(glFrustumfOES)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { + CALL_GL_API(glFrustumfOES, left, right, bottom, top, zNear, zFar); +} +void API_ENTRY(glOrthofOES)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) { + CALL_GL_API(glOrthofOES, left, right, bottom, top, zNear, zFar); +} +void API_ENTRY(glClipPlanefOES)(GLenum plane, const GLfloat *equation) { + CALL_GL_API(glClipPlanefOES, plane, equation); +} +void API_ENTRY(glGetClipPlanefOES)(GLenum pname, GLfloat eqn[4]) { + CALL_GL_API(glGetClipPlanefOES, pname, eqn); +} +void API_ENTRY(glClearDepthfOES)(GLclampf depth) { + CALL_GL_API(glClearDepthfOES, depth); +} +void API_ENTRY(glTexGenfOES)(GLenum coord, GLenum pname, GLfloat param) { + CALL_GL_API(glTexGenfOES, coord, pname, param); +} +void API_ENTRY(glTexGenfvOES)(GLenum coord, GLenum pname, const GLfloat *params) { + CALL_GL_API(glTexGenfvOES, coord, pname, params); +} +void API_ENTRY(glTexGeniOES)(GLenum coord, GLenum pname, GLint param) { + CALL_GL_API(glTexGeniOES, coord, pname, param); +} +void API_ENTRY(glTexGenivOES)(GLenum coord, GLenum pname, const GLint *params) { + CALL_GL_API(glTexGenivOES, coord, pname, params); +} +void API_ENTRY(glTexGenxOES)(GLenum coord, GLenum pname, GLfixed param) { + CALL_GL_API(glTexGenxOES, coord, pname, param); +} +void API_ENTRY(glTexGenxvOES)(GLenum coord, GLenum pname, const GLfixed *params) { + CALL_GL_API(glTexGenxvOES, coord, pname, params); +} +void API_ENTRY(glGetTexGenfvOES)(GLenum coord, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetTexGenfvOES, coord, pname, params); +} +void API_ENTRY(glGetTexGenivOES)(GLenum coord, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexGenivOES, coord, pname, params); +} +void API_ENTRY(glGetTexGenxvOES)(GLenum coord, GLenum pname, GLfixed *params) { + CALL_GL_API(glGetTexGenxvOES, coord, pname, params); +} diff --git a/opengl/libs/egl_entries.in b/opengl/libs/egl_entries.in index 33b4c654d207fc476455fd02dde2a32238f79293..3b4551b639646c1e2f3424d581ef53cd833d3850 100644 --- a/opengl/libs/egl_entries.in +++ b/opengl/libs/egl_entries.in @@ -43,3 +43,10 @@ EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGL /* EGL 1.3 */ /* EGL 1.4 */ + +/* EGL_EGLEXT_VERSION 3 */ + +EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint *) +EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface) +EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *) +EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR) diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index 62ce3fce17009b9d97562f1b684fdc8ab1f3256b..312b176015312721130e98027eecc3116c47e9d3 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -20,6 +20,8 @@ #include #include +#include +#include // ---------------------------------------------------------------------------- namespace android { diff --git a/opengl/libs/gl_entries.in b/opengl/libs/gl_entries.in index b97e8fe3c479db8a6b6822f7ce382f40f2bd30da..d7cc5da86bffc185e07db84e1e1cc8e7500d43cf 100644 --- a/opengl/libs/gl_entries.in +++ b/opengl/libs/gl_entries.in @@ -1,159 +1,145 @@ -GL_ENTRY(void, glColor4f, GLfloat, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glColor4x, GLfixed, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glNormal3f, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glNormal3x, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glCullFace, GLenum) -GL_ENTRY(void, glFrontFace, GLenum) -GL_ENTRY(void, glDisable, GLenum) -GL_ENTRY(void, glEnable, GLenum) -GL_ENTRY(void, glFinish, void) -GL_ENTRY(void, glFlush, void) -GL_ENTRY(GLenum, glGetError, void) -GL_ENTRY(const GLubyte*, glGetString, GLenum) -GL_ENTRY(void, glGetIntegerv, GLenum, GLint *) -GL_ENTRY(void, glColorMask, GLboolean, GLboolean, GLboolean, GLboolean) -GL_ENTRY(void, glDepthMask, GLboolean) -GL_ENTRY(void, glStencilMask, GLuint) -GL_ENTRY(void, glDepthFunc, GLenum) +GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref) +GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +GL_ENTRY(void, glClearDepthf, GLclampf depth) +GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar) -GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar) +GL_ENTRY(void, glFogf, GLenum pname, GLfloat param) +GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat eqn[4]) +GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params) +GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param) +GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param) +GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glLineWidth, GLfloat width) +GL_ENTRY(void, glLoadMatrixf, const GLfloat *m) +GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param) +GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glMultMatrixf, const GLfloat *m) +GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz) +GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param) +GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glPointSize, GLfloat size) GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units) -GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units) -GL_ENTRY(void, glLogicOp, GLenum opcode) +GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glActiveTexture, GLenum texture) GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref) -GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref) +GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer) +GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture) GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor) +GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) +GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) GL_ENTRY(void, glClear, GLbitfield mask) -GL_ENTRY(void, glClearColor, GLclampf r, GLclampf g, GLclampf b, GLclampf a) -GL_ENTRY(void, glClearColorx, GLclampx r, GLclampx g, GLclampx b, GLclampx a) -GL_ENTRY(void, glClearDepthf, GLclampf depth) +GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) GL_ENTRY(void, glClearDepthx, GLclampx depth) GL_ENTRY(void, glClearStencil, GLint s) -GL_ENTRY(void, glPointSize, GLfloat) -GL_ENTRY(void, glPointSizex, GLfixed) -GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert) -GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert) -GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask) -GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass) -GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height) -GL_ENTRY(void, glHint, GLenum, GLenum mode) -GL_ENTRY(void, glLineWidth, GLfloat width) +GL_ENTRY(void, glClientActiveTexture, GLenum texture) +GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation) +GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) +GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCullFace, GLenum mode) +GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers) +GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures) +GL_ENTRY(void, glDepthFunc, GLenum func) +GL_ENTRY(void, glDepthMask, GLboolean flag) +GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar) +GL_ENTRY(void, glDisable, GLenum cap) +GL_ENTRY(void, glDisableClientState, GLenum array) +GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count) +GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) +GL_ENTRY(void, glEnable, GLenum cap) +GL_ENTRY(void, glEnableClientState, GLenum array) +GL_ENTRY(void, glFinish, void) +GL_ENTRY(void, glFlush, void) +GL_ENTRY(void, glFogx, GLenum pname, GLfixed param) +GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glFrontFace, GLenum mode) +GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params) +GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed eqn[4]) +GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers) +GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures) +GL_ENTRY(GLenum, glGetError, void) +GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params) +GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetPointerv, GLenum pname, void **params) +GL_ENTRY(const GLubyte *, glGetString, GLenum name) +GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params) +GL_ENTRY(void, glHint, GLenum target, GLenum mode) +GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer) +GL_ENTRY(GLboolean, glIsEnabled, GLenum cap) +GL_ENTRY(GLboolean, glIsTexture, GLuint texture) +GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params) GL_ENTRY(void, glLineWidthx, GLfixed width) -GL_ENTRY(void, glShadeModel, GLenum) -GL_ENTRY(void, glLightModelf, GLenum, GLfloat) -GL_ENTRY(void, glLightModelfv, GLenum, const GLfloat *) -GL_ENTRY(void, glLightModelx, GLenum, GLfixed) -GL_ENTRY(void, glLightModelxv, GLenum, const GLfixed *) -GL_ENTRY(void, glLightf, GLenum, GLenum, GLfloat) -GL_ENTRY(void, glLightfv, GLenum, GLenum, const GLfloat *) -GL_ENTRY(void, glLightx, GLenum, GLenum, GLfixed) -GL_ENTRY(void, glLightxv, GLenum, GLenum, const GLfixed *) -GL_ENTRY(void, glMaterialf, GLenum, GLenum, GLfloat) -GL_ENTRY(void, glMaterialfv, GLenum, GLenum, const GLfloat *) -GL_ENTRY(void, glMaterialx, GLenum, GLenum, GLfixed) -GL_ENTRY(void, glMaterialxv, GLenum, GLenum, const GLfixed *) -GL_ENTRY(void, glFogf, GLenum, GLfloat) -GL_ENTRY(void, glFogfv, GLenum, const GLfloat *) -GL_ENTRY(void, glFogx, GLenum, GLfixed) -GL_ENTRY(void, glFogxv, GLenum, const GLfixed *) -GL_ENTRY(void, glVertexPointer, GLint, GLenum, GLsizei, const GLvoid *) -GL_ENTRY(void, glColorPointer, GLint, GLenum, GLsizei, const GLvoid *) -GL_ENTRY(void, glNormalPointer, GLenum, GLsizei, const GLvoid *) -GL_ENTRY(void, glTexCoordPointer, GLint, GLenum, GLsizei, const GLvoid *) -GL_ENTRY(void, glEnableClientState, GLenum) -GL_ENTRY(void, glDisableClientState, GLenum) -GL_ENTRY(void, glClientActiveTexture, GLenum) -GL_ENTRY(void, glDrawArrays, GLenum, GLint first, GLsizei) -GL_ENTRY(void, glDrawElements, GLenum, GLsizei, GLenum, const GLvoid *) GL_ENTRY(void, glLoadIdentity, void) -GL_ENTRY(void, glLoadMatrixf, const GLfloat*) -GL_ENTRY(void, glLoadMatrixx, const GLfixed*) +GL_ENTRY(void, glLoadMatrixx, const GLfixed *m) +GL_ENTRY(void, glLogicOp, GLenum opcode) +GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param) +GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params) GL_ENTRY(void, glMatrixMode, GLenum mode) -GL_ENTRY(void, glMultMatrixf, const GLfloat*) -GL_ENTRY(void, glMultMatrixx, const GLfixed*) +GL_ENTRY(void, glMultMatrixx, const GLfixed *m) +GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) +GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz) +GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param) +GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param) +GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glPointSizex, GLfixed size) +GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units) GL_ENTRY(void, glPopMatrix, void) GL_ENTRY(void, glPushMatrix, void) -GL_ENTRY(void, glFrustumf, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glFrustumx, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glOrthof, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glOrthox, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glRotatef, GLfloat, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glRotatex, GLfixed, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glScalef, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glScalex, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glTranslatef, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glTranslatex, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glViewport, GLint, GLint, GLsizei, GLsizei) -GL_ENTRY(void, glActiveTexture, GLenum) -GL_ENTRY(void, glBindTexture, GLenum, GLuint) -GL_ENTRY(void, glGenTextures, GLsizei, GLuint*) -GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *) -GL_ENTRY(void, glMultiTexCoord4f, GLenum, GLfloat, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glMultiTexCoord4x, GLenum, GLfixed, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glPixelStorei, GLenum, GLint) -GL_ENTRY(void, glTexEnvf, GLenum, GLenum, GLfloat) -GL_ENTRY(void, glTexEnvfv, GLenum, GLenum, const GLfloat*) -GL_ENTRY(void, glTexEnvx, GLenum, GLenum, GLfixed) -GL_ENTRY(void, glTexEnvxv, GLenum, GLenum, const GLfixed*) -GL_ENTRY(void, glTexParameterf, GLenum, GLenum, GLfloat) -GL_ENTRY(void, glTexParameterx, GLenum, GLenum, GLfixed) -GL_ENTRY(void, glCompressedTexImage2D, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*) -GL_ENTRY(void, glCompressedTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*) -GL_ENTRY(void, glCopyTexImage2D, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint) -GL_ENTRY(void, glCopyTexSubImage2D, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei) -GL_ENTRY(void, glTexImage2D, GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*) -GL_ENTRY(void, glTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*) -GL_ENTRY(void, glReadPixels, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *) - -// 1.1 additions -GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat*) -GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed*) -GL_ENTRY(void, glBindBuffer, GLenum, GLuint) -GL_ENTRY(void, glBufferData, GLenum, GLsizeiptr, const GLvoid*, GLenum) -GL_ENTRY(void, glBufferSubData, GLenum, GLintptr, GLsizeiptr, const GLvoid*) -GL_ENTRY(void, glDeleteBuffers, GLsizei, const GLuint*) -GL_ENTRY(void, glGenBuffers, GLsizei, GLuint*) -GL_ENTRY(void, glGetBooleanv, GLenum, GLboolean *) -GL_ENTRY(void, glGetFixedv, GLenum, GLfixed *) -GL_ENTRY(void, glGetFloatv, GLenum, GLfloat *) -GL_ENTRY(void, glGetPointerv, GLenum, void **) -GL_ENTRY(void, glGetBufferParameteriv, GLenum, GLenum, GLint *) -GL_ENTRY(void, glGetClipPlanef, GLenum, GLfloat[4]) -GL_ENTRY(void, glGetClipPlanex, GLenum, GLfixed[4]) -GL_ENTRY(void, glGetLightxv, GLenum, GLenum, GLfixed *) -GL_ENTRY(void, glGetLightfv, GLenum, GLenum, GLfloat *) -GL_ENTRY(void, glGetMaterialxv, GLenum, GLenum, GLfixed *) -GL_ENTRY(void, glGetMaterialfv, GLenum, GLenum, GLfloat *) -GL_ENTRY(void, glGetTexEnvfv, GLenum, GLenum, GLfloat *) -GL_ENTRY(void, glGetTexEnviv, GLenum, GLenum, GLint *) -GL_ENTRY(void, glGetTexEnvxv, GLenum, GLenum, GLfixed *) -GL_ENTRY(void, glGetTexParameterfv, GLenum, GLenum, GLfloat *) -GL_ENTRY(void, glGetTexParameteriv, GLenum, GLenum, GLint *) -GL_ENTRY(void, glGetTexParameterxv, GLenum, GLenum, GLfixed *) -GL_ENTRY(GLboolean, glIsBuffer, GLuint) -GL_ENTRY(GLboolean, glIsEnabled, GLenum) -GL_ENTRY(GLboolean, glIsTexture, GLuint) -GL_ENTRY(void, glPointParameterf, GLenum, GLfloat) -GL_ENTRY(void, glPointParameterfv, GLenum, const GLfloat *) -GL_ENTRY(void, glPointParameterx, GLenum, GLfixed) -GL_ENTRY(void, glPointParameterxv, GLenum, const GLfixed *) -GL_ENTRY(void, glColor4ub, GLubyte, GLubyte, GLubyte, GLubyte) -GL_ENTRY(void, glTexEnvi, GLenum, GLenum, GLint) -GL_ENTRY(void, glTexEnviv, GLenum, GLenum, const GLint *) -GL_ENTRY(void, glTexParameterfv, GLenum, GLenum, const GLfloat *) -GL_ENTRY(void, glTexParameteriv, GLenum, GLenum, const GLint *) -GL_ENTRY(void, glTexParameteri, GLenum, GLenum, GLint) -GL_ENTRY(void, glTexParameterxv, GLenum, GLenum, const GLfixed *) -GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid*) - -// Extensions -GL_ENTRY(void, glDrawTexsOES, GLshort, GLshort, GLshort, GLshort, GLshort) -GL_ENTRY(void, glDrawTexiOES, GLint, GLint, GLint, GLint, GLint) -GL_ENTRY(void, glDrawTexfOES, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat) -GL_ENTRY(void, glDrawTexxOES, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed) -GL_ENTRY(void, glDrawTexsvOES, const GLshort*) -GL_ENTRY(void, glDrawTexivOES, const GLint*) -GL_ENTRY(void, glDrawTexfvOES, const GLfloat*) -GL_ENTRY(void, glDrawTexxvOES, const GLfixed*) -GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed* mantissa, GLint* exponent) - +GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) +GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert) +GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert) +GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glShadeModel, GLenum mode) +GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilMask, GLuint mask) +GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass) +GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer) diff --git a/opengl/libs/gl_logger.h b/opengl/libs/gl_logger.h deleted file mode 100644 index ce85dd1ad0d74b4649c07799b55d523ab714ca90..0000000000000000000000000000000000000000 --- a/opengl/libs/gl_logger.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - ** 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. - */ - -#ifndef ANDROID_GL_LOGGER_H -#define ANDROID_GL_LOGGER_H - -namespace android { -#define GL_ENTRY(r, api, ...) r log_##api(__VA_ARGS__); -#include "gl_entries.in" -#undef GL_ENTRY -}; // namespace android - -#endif /* ANDROID_GL_LOGGER_H */ diff --git a/opengl/libs/glext_entries.in b/opengl/libs/glext_entries.in new file mode 100644 index 0000000000000000000000000000000000000000..dd09c71db54beff3993f2ee056ab72dda55a1a73 --- /dev/null +++ b/opengl/libs/glext_entries.in @@ -0,0 +1,90 @@ +GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glBlendEquationOES, GLenum mode) +GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) +GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height) +GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) +GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords) +GL_ENTRY(void, glDrawTexivOES, const GLint *coords) +GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords) +GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) +GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords) +GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref) +GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) +GL_ENTRY(void, glClearDepthxOES, GLclampx depth) +GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation) +GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) +GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar) +GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed eqn[4]) +GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params) +GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLineWidthxOES, GLfixed width) +GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m) +GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param) +GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m) +GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) +GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz) +GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glPointSizexOES, GLfixed size) +GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units) +GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert) +GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer) +GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer) +GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers) +GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers) +GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params) +GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer) +GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer) +GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers) +GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers) +GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target) +GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params) +GL_ENTRY(void, glGenerateMipmapOES, GLenum target) +GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access) +GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target) +GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void** params) +GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex) +GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void) +GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16]) +GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar) +GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat eqn[4]) +GL_ENTRY(void, glClearDepthfOES, GLclampf depth) +GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param) +GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params) diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h index 63fb017675bf1200474f841e3866190bb6ee8e5e..fd9725468a200f6e3cf5c9429c86e674a8d8d07f 100644 --- a/opengl/libs/hooks.h +++ b/opengl/libs/hooks.h @@ -22,9 +22,10 @@ #include #include +#include #include +#include -#define GL_LOGGER 0 #if !defined(__arm__) #define USE_SLOW_BINDING 1 #else @@ -35,7 +36,7 @@ #define MAX_NUMBER_OF_GL_EXTENSIONS 32 -#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && !GL_LOGGER && __OPTIMIZE__ +#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && __OPTIMIZE__ #define USE_FAST_TLS_KEY 1 #else #define USE_FAST_TLS_KEY 0 @@ -55,7 +56,10 @@ const unsigned int NUM_DISPLAYS = 1; enum { IMPL_HARDWARE = 0, IMPL_SOFTWARE, - IMPL_CONTEXT_LOST, + + IMPL_NUM_DRIVERS_IMPLEMENTATIONS, + + IMPL_CONTEXT_LOST = IMPL_NUM_DRIVERS_IMPLEMENTATIONS, IMPL_NO_CONTEXT, IMPL_NUM_IMPLEMENTATIONS @@ -73,6 +77,7 @@ enum { struct gl_hooks_t { struct gl_t { #include "gl_entries.in" + #include "glext_entries.in" } gl; struct egl_t { #include "egl_entries.in" diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles new file mode 100755 index 0000000000000000000000000000000000000000..107768bf5ced40392bc3b783ef8c1bc5a32a5748 --- /dev/null +++ b/opengl/libs/tools/genfiles @@ -0,0 +1,20 @@ +#! /bin/sh +# +# 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. + +./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in +./glentrygen ../../include/GLES/gl.h > ../gl_entries.in +./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in +./glentrygen ../../include/GLES/glext.h > ../glext_entries.in diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen new file mode 100755 index 0000000000000000000000000000000000000000..a2c3a7bff26d7488e1be6bd927bbbd68c1613714 --- /dev/null +++ b/opengl/libs/tools/glapigen @@ -0,0 +1,72 @@ +#! /usr/bin/perl +# +# 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. + +use strict; + +while (my $line = <>) { + next if $line =~ /^\//; + next if $line =~ /^#/; + next if $line =~ /^\s*$/; + if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) { + next; + } + my $type = $1; + my $name = $2; + my $args = $3; + + #printf("%s", $line); + + my $prefix = ""; + if ($name eq "glEGLImageTargetTexture2DOES") { + $prefix = "__"; + } + if ($name eq "glEGLImageTargetRenderbufferStorageOES") { + $prefix = "__"; + } + + printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args); + + printf(" {\n"); + if ($type eq "void") { + printf(" CALL_GL_API(%s", $name); + } else { + printf(" CALL_GL_API_RETURN(%s", $name); + } + my @args = split ',', $args; + my $len = scalar(@args); + for (my $num = 0; $num < $len; $num++) { + if ($args[$num] ne "void") { + print ", "; + # + # extract the name from the parameter + # type name + # const type *name + # type *name + # type name[4] + # + if ($args[$num] =~ /(\S+\s)+\**\s*([\w]+)/) { + printf("%s", $2); + } + } + } + printf(");\n"); + printf("}\n"); +} + + + + + diff --git a/opengl/libs/tools/glentrygen b/opengl/libs/tools/glentrygen new file mode 100755 index 0000000000000000000000000000000000000000..5e0f7b60d506b9d5e363f2ad9cff82665cf23bf2 --- /dev/null +++ b/opengl/libs/tools/glentrygen @@ -0,0 +1,31 @@ +#! /usr/bin/perl +# +# 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. + +use strict; + +while (my $line = <>) { + next if $line =~ /^\//; + next if $line =~ /^#/; + next if $line =~ /^\s*$/; + if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) { + next; + } + my $type = $1; + my $name = $2; + my $args = $3; + + printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args); +} diff --git a/opengl/tools/glgen/.gitignore b/opengl/tools/glgen/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..007ec6585c583701d00eb7eaf89bec3cb4f270fd --- /dev/null +++ b/opengl/tools/glgen/.gitignore @@ -0,0 +1,2 @@ +generated +out diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen index 1c498612afadeb747ab1fd25af41819f5e634140..011a6edf01e6c5e8f067df5500d2ca8464be2d26 100755 --- a/opengl/tools/glgen/gen +++ b/opengl/tools/glgen/gen @@ -1,28 +1,58 @@ -#!/bin/sh +#!/bin/bash +set -u +set -e rm -rf out generated mkdir out mkdir -p out/javax/microedition/khronos/opengles mkdir -p out/com/google/android/gles_jni mkdir -p out/android/graphics +mkdir -p out/android/opengl echo "package android.graphics;" > 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 +cp stubs/jsr239/GLHeader.java-if $GLFILE -GLGEN_FILES="CFunc.java CType.java CodeEmitter.java GenerateGL.java JFunc.java JType.java JniCodeEmitter.java ParameterChecker.java" +GLGEN_FILES="CFunc.java CType.java CodeEmitter.java GenerateGL.java GenerateGLES.java GLESCodeEmitter.java JFunc.java JniCodeEmitter.java JType.java Jsr239CodeEmitter.java ParameterChecker.java" pushd src > /dev/null javac ${GLGEN_FILES} +JAVAC_RESULT=$? +if [ $JAVAC_RESULT -ne 0 ]; then + echo "Could not compile glgen." + exit $JAVAC_RESULT +fi 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 + +echo "Generating JSR239-like APIs" +java -classpath src GenerateGL -c specs/jsr239/glspec-1.0 specs/jsr239/glspec-1.0ext specs/jsr239/glspec-1.1 specs/jsr239/glspec-1.1ext specs/jsr239/glspec-1.1extpack specs/jsr239/glspec-checks +JAVA_RESULT=$? +if [ $JAVA_RESULT -ne 0 ]; then + echo "Could not run GenerateGL." + exit $JAVA_RESULT +fi + +echo "Generating static OpenGLES 1.1 bindings" +java -classpath src GenerateGLES +JAVA_RESULT=$? +if [ $JAVA_RESULT -ne 0 ]; then + echo "Could not run GenerateGLES." + exit $JAVA_RESULT +fi + +rm src/*.class 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 +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 android/opengl/GLES10.java android/opengl/GLES10Ext.java android/opengl/GLES11.java android/opengl/GLES11Ext.java popd > /dev/null +JAVA_RESULT=$? +if [ $JAVA_RESULT -ne 0 ]; then + echo "Could not compile generated classes." + exit $JAVA_RESULT +fi rm -rf generated mkdir -p generated/C @@ -30,70 +60,44 @@ 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 +cp out/android_opengl_*.cpp generated/C +mkdir -p generated/android/opengl +cp -r out/android/opengl generated/android -# 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 +rm -rf out +KEEP_GENERATED=0 +SAID_PLEASE=0 + +# compareGenerated destDir generatedDir file +compareGenerated() { + if cmp -s $1/$3 $2/$3 ; then + echo "# " $3 unchanged + else + if [ $SAID_PLEASE == "0" ] ; then + echo Please evaluate the following commands: + echo + SAID_PLEASE=1 + fi + echo " " cp $2/$3 $1 + echo " " git add $1/$3 + KEEP_GENERATED=1 + fi +} + +compareGenerated ../../../core/jni generated/C com_google_android_gles_jni_GLImpl.cpp +compareGenerated ../../java/com/google/android/gles_jni generated/com/google/android/gles_jni GLImpl.java + +for x in GL.java GL10.java GL10Ext.java GL11.java GL11Ext.java GL11ExtensionPack.java +do + compareGenerated ../../java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x +done + +for x in GLES10 GLES10Ext GLES11 GLES11Ext +do + compareGenerated ../../java/android/opengl generated/android/opengl ${x}.java + compareGenerated ../../../core/jni generated/C android_opengl_${x}.cpp +done + +if [ $KEEP_GENERATED == "0" ] ; then + rm -rf generated fi - -rm -rf generated diff --git a/opengl/tools/glgen/specs/gles11/GLES10.spec b/opengl/tools/glgen/specs/gles11/GLES10.spec new file mode 100644 index 0000000000000000000000000000000000000000..8e1152d745e011793397939537f9937764d71bd6 --- /dev/null +++ b/opengl/tools/glgen/specs/gles11/GLES10.spec @@ -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/specs/gles11/GLES10Ext.spec b/opengl/tools/glgen/specs/gles11/GLES10Ext.spec new file mode 100644 index 0000000000000000000000000000000000000000..53f6c65699a2872da34656c4acb8914cf524fd55 --- /dev/null +++ b/opengl/tools/glgen/specs/gles11/GLES10Ext.spec @@ -0,0 +1 @@ +GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) diff --git a/opengl/tools/glgen/specs/gles11/GLES11.spec b/opengl/tools/glgen/specs/gles11/GLES11.spec new file mode 100644 index 0000000000000000000000000000000000000000..5527c183473687426ddc1e0456f4ee46e70b7685 --- /dev/null +++ b/opengl/tools/glgen/specs/gles11/GLES11.spec @@ -0,0 +1,44 @@ +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 glGetPointerv ( GLenum pname, void **params ) +void glGetTexEnvfv ( GLenum env, GLenum pname, GLfloat *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/specs/gles11/GLES11Ext.spec b/opengl/tools/glgen/specs/gles11/GLES11Ext.spec new file mode 100644 index 0000000000000000000000000000000000000000..cd7333a01be201db81169424ce85033915eb0461 --- /dev/null +++ b/opengl/tools/glgen/specs/gles11/GLES11Ext.spec @@ -0,0 +1,90 @@ +void glBlendEquationSeparateOES ( GLenum modeRGB, GLenum modeAlpha ) +void glBlendFuncSeparateOES ( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) +void glBlendEquationOES ( GLenum mode ) +void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height ) +void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height ) +void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height ) +void glDrawTexsvOES ( const GLshort *coords ) +void glDrawTexivOES ( const GLint *coords ) +void glDrawTexxvOES ( const GLfixed *coords ) +void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height ) +void glDrawTexfvOES ( const GLfloat *coords ) +void glEGLImageTargetTexture2DOES ( GLenum target, GLeglImageOES image ) +void glEGLImageTargetRenderbufferStorageOES ( GLenum target, GLeglImageOES image ) +void glAlphaFuncxOES ( GLenum func, GLclampx ref ) +void glClearColorxOES ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) +void glClearDepthxOES ( GLclampx depth ) +void glClipPlanexOES ( GLenum plane, const GLfixed *equation ) +void glColor4xOES ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) +void glDepthRangexOES ( GLclampx zNear, GLclampx zFar ) +void glFogxOES ( GLenum pname, GLfixed param ) +void glFogxvOES ( GLenum pname, const GLfixed *params ) +void glFrustumxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) +void glGetClipPlanexOES ( GLenum pname, GLfixed *eqn ) +void glGetFixedvOES ( GLenum pname, GLfixed *params ) +void glGetLightxvOES ( GLenum light, GLenum pname, GLfixed *params ) +void glGetMaterialxvOES ( GLenum face, GLenum pname, GLfixed *params ) +void glGetTexEnvxvOES ( GLenum env, GLenum pname, GLfixed *params ) +void glGetTexParameterxvOES ( GLenum target, GLenum pname, GLfixed *params ) +void glLightModelxOES ( GLenum pname, GLfixed param ) +void glLightModelxvOES ( GLenum pname, const GLfixed *params ) +void glLightxOES ( GLenum light, GLenum pname, GLfixed param ) +void glLightxvOES ( GLenum light, GLenum pname, const GLfixed *params ) +void glLineWidthxOES ( GLfixed width ) +void glLoadMatrixxOES ( const GLfixed *m ) +void glMaterialxOES ( GLenum face, GLenum pname, GLfixed param ) +void glMaterialxvOES ( GLenum face, GLenum pname, const GLfixed *params ) +void glMultMatrixxOES ( const GLfixed *m ) +void glMultiTexCoord4xOES ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) +void glNormal3xOES ( GLfixed nx, GLfixed ny, GLfixed nz ) +void glOrthoxOES ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) +void glPointParameterxOES ( GLenum pname, GLfixed param ) +void glPointParameterxvOES ( GLenum pname, const GLfixed *params ) +void glPointSizexOES ( GLfixed size ) +void glPolygonOffsetxOES ( GLfixed factor, GLfixed units ) +void glRotatexOES ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) +void glSampleCoveragexOES ( GLclampx value, GLboolean invert ) +void glScalexOES ( GLfixed x, GLfixed y, GLfixed z ) +void glTexEnvxOES ( GLenum target, GLenum pname, GLfixed param ) +void glTexEnvxvOES ( GLenum target, GLenum pname, const GLfixed *params ) +void glTexParameterxOES ( GLenum target, GLenum pname, GLfixed param ) +void glTexParameterxvOES ( GLenum target, GLenum pname, const GLfixed *params ) +void glTranslatexOES ( GLfixed x, GLfixed y, GLfixed z ) +GLboolean glIsRenderbufferOES ( GLuint renderbuffer ) +void glBindRenderbufferOES ( GLenum target, GLuint renderbuffer ) +void glDeleteRenderbuffersOES ( GLsizei n, const GLuint *renderbuffers ) +void glGenRenderbuffersOES ( GLsizei n, GLuint *renderbuffers ) +void glRenderbufferStorageOES ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) +void glGetRenderbufferParameterivOES ( GLenum target, GLenum pname, GLint *params ) +GLboolean glIsFramebufferOES ( GLuint framebuffer ) +void glBindFramebufferOES ( GLenum target, GLuint framebuffer ) +void glDeleteFramebuffersOES ( GLsizei n, const GLuint *framebuffers ) +void glGenFramebuffersOES ( GLsizei n, GLuint *framebuffers ) +GLenum glCheckFramebufferStatusOES ( GLenum target ) +void glFramebufferRenderbufferOES ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) +void glFramebufferTexture2DOES ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) +void glGetFramebufferAttachmentParameterivOES ( GLenum target, GLenum attachment, GLenum pname, GLint *params ) +void glGenerateMipmapOES ( GLenum target ) +// Hard to export to Java: +// void *glMapBufferOES ( GLenum target, GLenum access ) +// GLboolean glUnmapBufferOES ( GLenum target ) +// void glGetBufferPointervOES ( GLenum target, GLenum pname, void **params ) +void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) +void glLoadPaletteFromModelViewMatrixOES ( void ) +void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +void glDepthRangefOES ( GLclampf zNear, GLclampf zFar ) +void glFrustumfOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) +void glOrthofOES ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) +void glClipPlanefOES ( GLenum plane, const GLfloat *equation ) +void glGetClipPlanefOES ( GLenum pname, GLfloat *eqn ) +void glClearDepthfOES ( GLclampf depth ) +void glTexGenfOES ( GLenum coord, GLenum pname, GLfloat param ) +void glTexGenfvOES ( GLenum coord, GLenum pname, const GLfloat *params ) +void glTexGeniOES ( GLenum coord, GLenum pname, GLint param ) +void glTexGenivOES ( GLenum coord, GLenum pname, const GLint *params ) +void glTexGenxOES ( GLenum coord, GLenum pname, GLfixed param ) +void glTexGenxvOES ( GLenum coord, GLenum pname, const GLfixed *params ) +void glGetTexGenfvOES ( GLenum coord, GLenum pname, GLfloat *params ) +void glGetTexGenivOES ( GLenum coord, GLenum pname, GLint *params ) +void glGetTexGenxvOES ( GLenum coord, GLenum pname, GLfixed *params ) diff --git a/opengl/tools/glgen/specs/gles11/checks.spec b/opengl/tools/glgen/specs/gles11/checks.spec new file mode 100644 index 0000000000000000000000000000000000000000..e31a2ce50e03ed1336ceae17d8b4e88bcff4b551 --- /dev/null +++ b/opengl/tools/glgen/specs/gles11/checks.spec @@ -0,0 +1,61 @@ +glClipPlanef check eqn 4 +glClipPlanex check eqn 4 +glGetClipPlanefOES check eqn 4 +glGetClipPlanexOES check eqn 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_COLOR_CONTROL,GL_LIGHT_MODEL_LOCAL_VIEWER,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_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT,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 getNumCompressedTextureFormats() pname GL_COMPRESSED_TEXTURE_FORMATS +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/glspec-1.0 b/opengl/tools/glgen/specs/jsr239/glspec-1.0 similarity index 100% rename from opengl/tools/glgen/glspec-1.0 rename to opengl/tools/glgen/specs/jsr239/glspec-1.0 diff --git a/opengl/tools/glgen/glspec-1.0ext b/opengl/tools/glgen/specs/jsr239/glspec-1.0ext similarity index 100% rename from opengl/tools/glgen/glspec-1.0ext rename to opengl/tools/glgen/specs/jsr239/glspec-1.0ext diff --git a/opengl/tools/glgen/glspec-1.1 b/opengl/tools/glgen/specs/jsr239/glspec-1.1 similarity index 100% rename from opengl/tools/glgen/glspec-1.1 rename to opengl/tools/glgen/specs/jsr239/glspec-1.1 diff --git a/opengl/tools/glgen/glspec-1.1ext b/opengl/tools/glgen/specs/jsr239/glspec-1.1ext similarity index 100% rename from opengl/tools/glgen/glspec-1.1ext rename to opengl/tools/glgen/specs/jsr239/glspec-1.1ext diff --git a/opengl/tools/glgen/glspec-1.1extpack b/opengl/tools/glgen/specs/jsr239/glspec-1.1extpack similarity index 100% rename from opengl/tools/glgen/glspec-1.1extpack rename to opengl/tools/glgen/specs/jsr239/glspec-1.1extpack diff --git a/opengl/tools/glgen/glspec-checks b/opengl/tools/glgen/specs/jsr239/glspec-checks similarity index 60% rename from opengl/tools/glgen/glspec-checks rename to opengl/tools/glgen/specs/jsr239/glspec-checks index a84ed65332a364ce439e5c1bb4e080b719a9bc38..55840fa101437e2e48c4e62b67686f844da1a168 100644 --- a/opengl/tools/glgen/glspec-checks +++ b/opengl/tools/glgen/specs/jsr239/glspec-checks @@ -7,7 +7,7 @@ glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END 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 +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_COLOR_CONTROL,GL_LIGHT_MODEL_LOCAL_VIEWER,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_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT,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 getNumCompressedTextureFormats() pname GL_COMPRESSED_TEXTURE_FORMATS 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 diff --git a/opengl/tools/glgen/src/.gitignore b/opengl/tools/glgen/src/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6b468b62a9884e67ca19b673f8e14e1931d65036 --- /dev/null +++ b/opengl/tools/glgen/src/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/opengl/tools/glgen/src/CFunc.java b/opengl/tools/glgen/src/CFunc.java index 0794f417427bc89264646ac404fd3a0f107d8180..a89e1c59e4a5d8ce0d40e68d59125977506e341d 100644 --- a/opengl/tools/glgen/src/CFunc.java +++ b/opengl/tools/glgen/src/CFunc.java @@ -1,155 +1,156 @@ - -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; - } -} + +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; + } + + @Override + 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 index 331ec625a5e0ee1e1bffa36b919273c82abc458c..826c90d46f19baff0696a58b075a34ab69c38bab 100644 --- a/opengl/tools/glgen/src/CType.java +++ b/opengl/tools/glgen/src/CType.java @@ -1,85 +1,88 @@ - -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; - } -} + +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; + } + + @Override + public String toString() { + String s = ""; + if (isConst()) { + s += "const "; + } + s += baseType; + if (isPointer()) { + s += "*"; + } + + return s; + } + + @Override + public int hashCode() { + return baseType.hashCode() ^ (isPointer ? 2 : 0) ^ (isConst ? 1 : 0); + } + + @Override + 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 index 3e9b90aab881abbf179c4ab9f3c39d81f2782636..ebb97277e55f92e90bb9d59b63b9b8ba302cee3d 100644 --- a/opengl/tools/glgen/src/CodeEmitter.java +++ b/opengl/tools/glgen/src/CodeEmitter.java @@ -1,8 +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(); -} + +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/GLESCodeEmitter.java b/opengl/tools/glgen/src/GLESCodeEmitter.java new file mode 100644 index 0000000000000000000000000000000000000000..b303503ccc0f094e38c258c0290aee7c50eeadf8 --- /dev/null +++ b/opengl/tools/glgen/src/GLESCodeEmitter.java @@ -0,0 +1,40 @@ +import java.io.PrintStream; + +/** + * 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 GLESCodeEmitter extends JniCodeEmitter { + + PrintStream mJavaImplStream; + PrintStream mCStream; + + PrintStream mJavaInterfaceStream; + + /** + */ + public GLESCodeEmitter(String classPathName, + ParameterChecker checker, + PrintStream javaImplStream, + PrintStream cStream) { + mClassPathName = classPathName; + mChecker = checker; + + mJavaImplStream = javaImplStream; + mCStream = cStream; + mUseContextPointer = false; + mUseStaticMethods = true; + } + + public void emitCode(CFunc cfunc, String original) { + emitCode(cfunc, original, null, mJavaImplStream, + mCStream); + } + + public void emitNativeRegistration(String nativeRegistrationName) { + emitNativeRegistration(nativeRegistrationName, mCStream); + } +} diff --git a/opengl/tools/glgen/src/GenerateGL.java b/opengl/tools/glgen/src/GenerateGL.java index 657ee6e7c7e0c6590daf712e71c3a50ccb890b84..3715a96fc38fbb83e12562ef782e161594b71dbc 100644 --- a/opengl/tools/glgen/src/GenerateGL.java +++ b/opengl/tools/glgen/src/GenerateGL.java @@ -1,164 +1,167 @@ - -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("}"); - } -} + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; + +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; + while ((s = specReader.readLine()) != null) { + if (s.trim().startsWith("//")) { + continue; + } + + CFunc cfunc = CFunc.parseCFunc(s); + + String fname = cfunc.getName(); + File f = new File("stubs/jsr239/" + fname + + ".java-1" + version + "-if"); + if (f.exists()) { + System.out.println("Special-casing function " + fname); + copy("stubs/jsr239/" + fname + + ".java-1" + version + "-if", glStream); + copy("stubs/jsr239/" + fname + ".java-impl", glImplStream); + copy("stubs/jsr239/" + fname + ".cpp", cStream); + + // Register native function names + // This should be improved to require fewer discrete files + String filename = "stubs/jsr239/" + 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 Jsr239CodeEmitter(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/jsr239/GL10Header.java-if", gl10Stream); + copy("stubs/jsr239/GL10ExtHeader.java-if", gl10ExtStream); + copy("stubs/jsr239/GL11Header.java-if", gl11Stream); + copy("stubs/jsr239/GL11ExtHeader.java-if", gl11ExtStream); + copy("stubs/jsr239/GL11ExtensionPackHeader.java-if", gl11ExtPackStream); + copy("stubs/jsr239/GLImplHeader.java-impl", glImplStream); + copy("stubs/jsr239/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/GenerateGLES.java b/opengl/tools/glgen/src/GenerateGLES.java new file mode 100644 index 0000000000000000000000000000000000000000..60775b7b4122e977f87562a865a3cc48eed773f6 --- /dev/null +++ b/opengl/tools/glgen/src/GenerateGLES.java @@ -0,0 +1,99 @@ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; + +public class GenerateGLES { + + 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(GLESCodeEmitter emitter, + BufferedReader specReader, + PrintStream glStream, + PrintStream cStream) throws Exception { + String s = null; + while ((s = specReader.readLine()) != null) { + if (s.trim().startsWith("//")) { + continue; + } + + CFunc cfunc = CFunc.parseCFunc(s); + + String fname = cfunc.getName(); + String stubRoot = "stubs/gles11/" + fname; + String javaPath = stubRoot + ".java"; + File f = new File(javaPath); + if (f.exists()) { + System.out.println("Special-casing function " + fname); + copy(javaPath, glStream); + copy(stubRoot + ".cpp", cStream); + + // Register native function names + // This should be improved to require fewer discrete files + String filename = stubRoot + ".nativeReg"; + BufferedReader br = + new BufferedReader(new FileReader(filename)); + String nfunc; + while ((nfunc = br.readLine()) != null) { + emitter.addNativeRegistration(nfunc); + } + } else { + emitter.emitCode(cfunc, s); + } + } + } + + public static void main(String[] args) throws Exception { + int aidx = 0; + while ((aidx < args.length) && (args[aidx].charAt(0) == '-')) { + switch (args[aidx].charAt(1)) { + default: + System.err.println("Unknown flag: " + args[aidx]); + System.exit(1); + } + + aidx++; + } + + BufferedReader checksReader = + new BufferedReader(new FileReader("specs/gles11/checks.spec")); + ParameterChecker checker = new ParameterChecker(checksReader); + + // Generate files + for(String suffix: new String[] {"GLES10", "GLES10Ext", + "GLES11", "GLES11Ext"}) + { + BufferedReader spec11Reader = + new BufferedReader(new FileReader("specs/gles11/" + + suffix + ".spec")); + String gl11Filename = "android/opengl/" + suffix + ".java"; + String gl11cFilename = "android_opengl_" + suffix + ".cpp"; + PrintStream gl11Stream = + new PrintStream(new FileOutputStream("out/" + gl11Filename)); + PrintStream gl11cStream = + new PrintStream(new FileOutputStream("out/" + gl11cFilename)); + gl11Stream.println("/*"); + gl11cStream.println("/*"); + copy("stubs/gles11/" + suffix + "Header.java-if", gl11Stream); + copy("stubs/gles11/" + suffix + "cHeader.cpp", gl11cStream); + GLESCodeEmitter emitter = new GLESCodeEmitter( + "android/opengl/" + suffix, + checker, gl11Stream, gl11cStream); + emit(emitter, spec11Reader, gl11Stream, gl11cStream); + emitter.emitNativeRegistration("register_android_opengl_jni_" + + suffix); + gl11Stream.println("}"); + gl11Stream.close(); + gl11cStream.close(); + } + } +} diff --git a/opengl/tools/glgen/src/JFunc.java b/opengl/tools/glgen/src/JFunc.java index 42d466c33ed6d4e8e6637378f756b5761da55aed..63c045b21e8f92f2979e117a6b5839c312e61daa 100644 --- a/opengl/tools/glgen/src/JFunc.java +++ b/opengl/tools/glgen/src/JFunc.java @@ -1,148 +1,154 @@ - -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; - } - -} + +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) { + try { + 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; + } catch (RuntimeException e) { + System.err.println("Failed to convert function " + cfunc); + throw e; + } + } + + @Override + 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 index a16d4400d83f8ebe23f51bcf7eeabbd860cfe3d3..df1177bfd5c1e825d0301c5fd9c827ce1d4fe806 100644 --- a/opengl/tools/glgen/src/JType.java +++ b/opengl/tools/glgen/src/JType.java @@ -1,139 +1,142 @@ - -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; - } -} + +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)); + typeMapping.put(new CType("GLeglImageOES", false, false), + 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; + } + + @Override + 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 index 33b9a3e538f617d6a8704146eaf197f4d8f8fa9c..b0997b15a1d6dec0228f8c99aa5fea10929727e5 100644 --- a/opengl/tools/glgen/src/JniCodeEmitter.java +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -1,99 +1,55 @@ 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(); +public class JniCodeEmitter { + static final boolean mUseCPlusPlus = true; + protected boolean mUseContextPointer = true; + protected boolean mUseStaticMethods = false; + protected String mClassPathName; + protected ParameterChecker mChecker; + protected List nativeRegistrations = new ArrayList(); boolean needsExit; - - static String indent = " "; - + protected 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 static String getJniName(JType jType) { + String jniName = ""; + if (jType.isClass()) { + return "L" + jType.getBaseType() + ";"; + } else if (jType.isArray()) { + jniName = "["; + } - 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); + 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; } - public void emitCode(CFunc cfunc, String original) { + + public void emitCode(CFunc cfunc, String original, + PrintStream javaInterfaceStream, + PrintStream javaImplStream, + PrintStream cStream) { JFunc jfunc; String signature; boolean duplicate; - + if (cfunc.hasTypedPointerArg()) { jfunc = JFunc.convert(cfunc, true); @@ -109,12 +65,14 @@ public class JniCodeEmitter implements CodeEmitter { } if (!duplicate) { - emitNativeDeclaration(jfunc, mJavaImplStream); - emitJavaCode(jfunc, mJavaImplStream); + emitNativeDeclaration(jfunc, javaImplStream); + emitJavaCode(jfunc, javaImplStream); + } + if (javaInterfaceStream != null) { + emitJavaInterfaceCode(jfunc, javaInterfaceStream); } - emitJavaInterfaceCode(jfunc, mJavaInterfaceStream); if (!duplicate) { - emitJniCode(jfunc, mCStream); + emitJniCode(jfunc, cStream); } } @@ -129,12 +87,14 @@ public class JniCodeEmitter implements CodeEmitter { } if (!duplicate) { - emitNativeDeclaration(jfunc, mJavaImplStream); + emitNativeDeclaration(jfunc, javaImplStream); + } + if (javaInterfaceStream != null) { + emitJavaInterfaceCode(jfunc, javaInterfaceStream); } - emitJavaInterfaceCode(jfunc, mJavaInterfaceStream); if (!duplicate) { - emitJavaCode(jfunc, mJavaImplStream); - emitJniCode(jfunc, mCStream); + emitJavaCode(jfunc, javaImplStream); + emitJniCode(jfunc, cStream); } } @@ -152,8 +112,8 @@ public class JniCodeEmitter implements CodeEmitter { public void emitJavaCode(JFunc jfunc, PrintStream out) { emitFunction(jfunc, out, false, false); } - - void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray ) { + + void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) { boolean isVoid = jfunc.getType().isVoid(); boolean isPointerFunc = jfunc.getName().endsWith("Pointer") && jfunc.getCFunc().hasPointerArg(); @@ -167,7 +127,7 @@ public class JniCodeEmitter implements CodeEmitter { jfunc.getName() + (isPointerFunc ? "Bounds" : "" ) + "("); - + int numArgs = jfunc.getNumArgs(); for (int i = 0; i < numArgs; i++) { String argName = jfunc.getArgName(i); @@ -177,7 +137,7 @@ public class JniCodeEmitter implements CodeEmitter { 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 + ")"); + out.print(iii + indent + "getOffset(" + argName + ")"); } else { out.print(iii + indent + argName); } @@ -192,41 +152,40 @@ public class JniCodeEmitter implements CodeEmitter { 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 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 + "}"); + 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 + "}"); - } + 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()); @@ -312,115 +271,106 @@ public class JniCodeEmitter implements CodeEmitter { } 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;"); + boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { + + String[] checks = mChecker.getChecks(cfunc.getName()); + + boolean lastWasIfcheck = false; + + int index = 1; + if (checks != null) { + 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"; } - 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 + 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); + } } - 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); - } - } + if (lastWasIfcheck) { + printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); + } + } - boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, - List nonPrimitiveArgs) { + 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(); @@ -439,7 +389,7 @@ public class JniCodeEmitter implements CodeEmitter { return false; } - + /** * Emit a function in several variants: * @@ -449,9 +399,7 @@ public class JniCodeEmitter implements CodeEmitter { * if interfaceDecl: public func(args); * if !interfaceDecl: public func(args) { body } */ - void emitFunction(JFunc jfunc, - PrintStream out, - boolean nativeDecl, boolean interfaceDecl) { + void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) { boolean isPointerFunc = jfunc.getName().endsWith("Pointer") && jfunc.getCFunc().hasPointerArg(); @@ -462,28 +410,30 @@ public class JniCodeEmitter implements CodeEmitter { return; } + String maybeStatic = mUseStaticMethods ? "static " : ""; + if (isPointerFunc) { out.println(indent + - (nativeDecl ? "private native " : - (interfaceDecl ? "" : "public ")) + + (nativeDecl ? "private " + maybeStatic +"native " : + (interfaceDecl ? "" : "public ") + maybeStatic) + jfunc.getType() + " " + jfunc.getName() + (nativeDecl ? "Bounds" : "") + "("); } else { out.println(indent + - (nativeDecl ? "public native " : - (interfaceDecl ? "" : "public ")) + + (nativeDecl ? "public " + maybeStatic +"native " : + (interfaceDecl ? "" : "public ") + maybeStatic) + 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) { @@ -504,6 +454,15 @@ public class JniCodeEmitter implements CodeEmitter { String iii = indent + indent; + // emitBoundsChecks(jfunc, out, iii); + emitFunctionCall(jfunc, out, iii, false); + + // Set the pointer after we call the native code, so that if + // the native code throws an exception we don't modify the + // pointer. We assume that the native code is written so that + // if an exception is thrown, then the underlying glXXXPointer + // function will not have been called. + String fname = jfunc.getName(); if (isPointerFunc) { // TODO - deal with VBO variants @@ -548,9 +507,6 @@ public class JniCodeEmitter implements CodeEmitter { } } - // emitBoundsChecks(jfunc, out, iii); - emitFunctionCall(jfunc, out, iii, false); - boolean isVoid = jfunc.getType().isVoid(); if (!isVoid) { @@ -561,29 +517,44 @@ public class JniCodeEmitter implements CodeEmitter { 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"; + public void addNativeRegistration(String s) { + nativeRegistrations.add(s); + } + + public void emitNativeRegistration(String registrationFunctionName, + PrintStream cStream) { + cStream.println("static const char *classPathName = \"" + + mClassPathName + + "\";"); + cStream.println(); + + cStream.println("static JNINativeMethod methods[] = {"); + + cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); + + Iterator i = nativeRegistrations.iterator(); + while (i.hasNext()) { + cStream.println(i.next()); } - return jniName; + + cStream.println("};"); + cStream.println(); + + + cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)"); + cStream.println("{"); + cStream.println(indent + + "int err;"); + + cStream.println(indent + + "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); + + cStream.println(indent + "return err;"); + cStream.println("}"); + } + + public JniCodeEmitter() { + super(); } String getJniType(JType jType) { @@ -604,7 +575,7 @@ public class JniCodeEmitter implements CodeEmitter { return "jobject"; } } - + String getJniMangledName(String name) { name = name.replaceAll("_", "_1"); name = name.replaceAll(";", "_2"); @@ -614,7 +585,7 @@ public class JniCodeEmitter implements CodeEmitter { public void emitJniCode(JFunc jfunc, PrintStream out) { CFunc cfunc = jfunc.getCFunc(); - + // Emit comment identifying original C function // // Example: @@ -658,13 +629,13 @@ public class JniCodeEmitter implements CodeEmitter { } // Append signature to function name - String sig = getJniMangledName(signature).replace('.', '_'); + String sig = getJniMangledName(signature).replace('.', '_'); out.print("__" + sig); outName += "__" + sig; - + signature = signature.replace('.', '/'); rsignature = rsignature.replace('.', '/'); - + out.println(); if (rsignature.length() == 0) { rsignature = "V"; @@ -718,13 +689,11 @@ public class JniCodeEmitter implements CodeEmitter { 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; } @@ -740,7 +709,7 @@ public class JniCodeEmitter implements CodeEmitter { // Example: // // android::gl::ogles_context_t *ctx; - // + // // jint _exception; // GLenum _returnValue; // @@ -827,15 +796,13 @@ public class JniCodeEmitter implements CodeEmitter { out.println(indent + decl + (decl.endsWith("*") ? "" : " ") + - jfunc.getArgName(idx) + + jfunc.getArgName(idx) + " = (" + decl + ") 0;"); } out.println(); } - String retval = isVoid ? "" : " _returnValue"; - // Emit 'GetPrimitiveArrayCritical' for arrays // Emit 'GetPointer' calls for Buffer pointers int bufArgIdx = 0; @@ -843,7 +810,7 @@ public class JniCodeEmitter implements CodeEmitter { 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"; @@ -852,7 +819,7 @@ public class JniCodeEmitter implements CodeEmitter { if (jfunc.getArgType(idx).isArray()) { out.println(indent + - "if (!" + + "if (!" + cname + "_ref) {"); if (emitExceptionCheck) { @@ -884,7 +851,7 @@ public class JniCodeEmitter implements CodeEmitter { out.println(indent + "}"); out.println(indent + remaining + " = " + - (mUseCPlusPlus ? "_env" : "(*_env)") + + (mUseCPlusPlus ? "_env" : "(*_env)") + "->GetArrayLength(" + (mUseCPlusPlus ? "" : "_env, ") + cname + "_ref) - " + offset + ";"); @@ -901,7 +868,7 @@ public class JniCodeEmitter implements CodeEmitter { out.println(indent + " " + (mUseCPlusPlus ? "_env" : "(*_env)") + "->GetPrimitiveArrayCritical(" + - (mUseCPlusPlus ? "" : "_env, ") + + (mUseCPlusPlus ? "" : "_env, ") + jfunc.getArgName(idx) + "_ref, (jboolean *)0);"); out.println(indent + @@ -912,19 +879,39 @@ public class JniCodeEmitter implements CodeEmitter { String array = numBufferArgs <= 1 ? "_array" : "_" + bufferArgNames.get(bufArgIdx++) + "Array"; - boolean nullAllowed = isNullAllowed(cfunc); + boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; if (nullAllowed) { out.println(indent + "if (" + cname + "_buf) {"); out.print(indent); } - - out.println(indent + + + if (isPointerFunc) { + out.println(indent + cname + " = (" + cfunc.getArgType(cIndex).getDeclaration() + - ")getPointer(_env, " + - cname + - "_buf, &" + array + ", &" + remaining + ");"); + ") _env->GetDirectBufferAddress(" + + (mUseCPlusPlus ? "" : "_env, ") + + cname + "_buf);"); + String iii = " "; + out.println(iii + indent + "if ( ! " + cname + " ) {"); + out.println(iii + iii + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + "IAEClass, \"Must use a native order direct Buffer\");"); + out.println(iii + iii + indent + "return;"); + out.println(iii + indent + "}"); + } else { + out.println(indent + + cname + + " = (" + + cfunc.getArgType(cIndex).getDeclaration() + + ")getPointer(_env, " + + cname + + "_buf, &" + array + ", &" + remaining + + ");"); + } if (nullAllowed) { out.println(indent + "}"); @@ -950,10 +937,10 @@ public class JniCodeEmitter implements CodeEmitter { name.substring(1, name.length()); out.print("ctx->procs."); } - + out.print(name + (isPointerFunc ? "Bounds" : "") + "("); - numArgs = cfunc.getNumArgs(); + numArgs = cfunc.getNumArgs(); if (numArgs == 0) { if (mUseContextPointer) { out.println("ctx);"); @@ -1006,7 +993,7 @@ public class JniCodeEmitter implements CodeEmitter { 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 @@ -1015,7 +1002,7 @@ public class JniCodeEmitter implements CodeEmitter { out.println(indent + indent + (mUseCPlusPlus ? "_env" : "(*_env)") + "->ReleasePrimitiveArrayCritical(" + - (mUseCPlusPlus ? "" : "_env, ") + + (mUseCPlusPlus ? "" : "_env, ") + jfunc.getArgName(idx) + "_ref, " + cfunc.getArgName(cIndex) + "_base,"); @@ -1026,17 +1013,20 @@ public class JniCodeEmitter implements CodeEmitter { ");"); 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 (! isPointerFunc) { + 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 + "}"); + } } } } @@ -1049,38 +1039,4 @@ public class JniCodeEmitter implements CodeEmitter { 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/Jsr239CodeEmitter.java b/opengl/tools/glgen/src/Jsr239CodeEmitter.java new file mode 100644 index 0000000000000000000000000000000000000000..335d2269aba15dd302c6afd6af20f0e823b0333e --- /dev/null +++ b/opengl/tools/glgen/src/Jsr239CodeEmitter.java @@ -0,0 +1,74 @@ +import java.io.PrintStream; + +/** + * 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 Jsr239CodeEmitter extends JniCodeEmitter implements CodeEmitter { + + PrintStream mJava10InterfaceStream; + PrintStream mJava10ExtInterfaceStream; + PrintStream mJava11InterfaceStream; + PrintStream mJava11ExtInterfaceStream; + PrintStream mJava11ExtPackInterfaceStream; + PrintStream mJavaImplStream; + PrintStream mCStream; + + PrintStream mJavaInterfaceStream; + + /** + * @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 Jsr239CodeEmitter(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) { + emitCode(cfunc, original, mJavaInterfaceStream, mJavaImplStream, mCStream); + } + + public void emitNativeRegistration() { + emitNativeRegistration("register_com_google_android_gles_jni_GLImpl", mCStream); + } +} diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtHeader.java-if b/opengl/tools/glgen/stubs/gles11/GLES10ExtHeader.java-if new file mode 100644 index 0000000000000000000000000000000000000000..42891eae3b8fdca32a905b08dabb82c912481d52 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtHeader.java-if @@ -0,0 +1,26 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +public class GLES10Ext { + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + \ No newline at end of file diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..294d1ce82e72b83f63fa2aaf61becdb001415613 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp @@ -0,0 +1,125 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +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. */ + +static 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/gles11/GLES10Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES10Header.java-if new file mode 100644 index 0000000000000000000000000000000000000000..4b2a83106c95a43fa42505cd6d6845e541be54bd --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES10Header.java-if @@ -0,0 +1,271 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +import java.nio.Buffer; + +public class GLES10 { + public static final int GL_ADD = 0x0104; + public static final int GL_ALIASED_LINE_WIDTH_RANGE = 0x846E; + public static final int GL_ALIASED_POINT_SIZE_RANGE = 0x846D; + public static final int GL_ALPHA = 0x1906; + public static final int GL_ALPHA_BITS = 0x0D55; + public static final int GL_ALPHA_TEST = 0x0BC0; + public static final int GL_ALWAYS = 0x0207; + public static final int GL_AMBIENT = 0x1200; + public static final int GL_AMBIENT_AND_DIFFUSE = 0x1602; + public static final int GL_AND = 0x1501; + public static final int GL_AND_INVERTED = 0x1504; + public static final int GL_AND_REVERSE = 0x1502; + public static final int GL_BACK = 0x0405; + public static final int GL_BLEND = 0x0BE2; + public static final int GL_BLUE_BITS = 0x0D54; + public static final int GL_BYTE = 0x1400; + public static final int GL_CCW = 0x0901; + public static final int GL_CLAMP_TO_EDGE = 0x812F; + public static final int GL_CLEAR = 0x1500; + public static final int GL_COLOR_ARRAY = 0x8076; + public static final int GL_COLOR_BUFFER_BIT = 0x4000; + public static final int GL_COLOR_LOGIC_OP = 0x0BF2; + public static final int GL_COLOR_MATERIAL = 0x0B57; + public static final int GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; + public static final int GL_CONSTANT_ATTENUATION = 0x1207; + public static final int GL_COPY = 0x1503; + public static final int GL_COPY_INVERTED = 0x150C; + public static final int GL_CULL_FACE = 0x0B44; + public static final int GL_CW = 0x0900; + public static final int GL_DECAL = 0x2101; + public static final int GL_DECR = 0x1E03; + public static final int GL_DEPTH_BITS = 0x0D56; + public static final int GL_DEPTH_BUFFER_BIT = 0x0100; + public static final int GL_DEPTH_TEST = 0x0B71; + public static final int GL_DIFFUSE = 0x1201; + public static final int GL_DITHER = 0x0BD0; + public static final int GL_DONT_CARE = 0x1100; + public static final int GL_DST_ALPHA = 0x0304; + public static final int GL_DST_COLOR = 0x0306; + public static final int GL_EMISSION = 0x1600; + public static final int GL_EQUAL = 0x0202; + public static final int GL_EQUIV = 0x1509; + public static final int GL_EXP = 0x0800; + public static final int GL_EXP2 = 0x0801; + public static final int GL_EXTENSIONS = 0x1F03; + public static final int GL_FALSE = 0; + public static final int GL_FASTEST = 0x1101; + public static final int GL_FIXED = 0x140C; + public static final int GL_FLAT = 0x1D00; + public static final int GL_FLOAT = 0x1406; + public static final int GL_FOG = 0x0B60; + public static final int GL_FOG_COLOR = 0x0B66; + public static final int GL_FOG_DENSITY = 0x0B62; + public static final int GL_FOG_END = 0x0B64; + public static final int GL_FOG_HINT = 0x0C54; + public static final int GL_FOG_MODE = 0x0B65; + public static final int GL_FOG_START = 0x0B63; + public static final int GL_FRONT = 0x0404; + public static final int GL_FRONT_AND_BACK = 0x0408; + public static final int GL_GEQUAL = 0x0206; + public static final int GL_GREATER = 0x0204; + public static final int GL_GREEN_BITS = 0x0D53; + public static final int GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES = 0x8B9B; + public static final int GL_IMPLEMENTATION_COLOR_READ_TYPE_OES = 0x8B9A; + public static final int GL_INCR = 0x1E02; + public static final int GL_INVALID_ENUM = 0x0500; + public static final int GL_INVALID_OPERATION = 0x0502; + public static final int GL_INVALID_VALUE = 0x0501; + public static final int GL_INVERT = 0x150A; + public static final int GL_KEEP = 0x1E00; + public static final int GL_LEQUAL = 0x0203; + public static final int GL_LESS = 0x0201; + public static final int GL_LIGHT_MODEL_AMBIENT = 0x0B53; + public static final int GL_LIGHT_MODEL_TWO_SIDE = 0x0B52; + public static final int GL_LIGHT0 = 0x4000; + public static final int GL_LIGHT1 = 0x4001; + public static final int GL_LIGHT2 = 0x4002; + public static final int GL_LIGHT3 = 0x4003; + public static final int GL_LIGHT4 = 0x4004; + public static final int GL_LIGHT5 = 0x4005; + public static final int GL_LIGHT6 = 0x4006; + public static final int GL_LIGHT7 = 0x4007; + public static final int GL_LIGHTING = 0x0B50; + public static final int GL_LINE_LOOP = 0x0002; + public static final int GL_LINE_SMOOTH = 0x0B20; + public static final int GL_LINE_SMOOTH_HINT = 0x0C52; + public static final int GL_LINE_STRIP = 0x0003; + public static final int GL_LINEAR = 0x2601; + public static final int GL_LINEAR_ATTENUATION = 0x1208; + public static final int GL_LINEAR_MIPMAP_LINEAR = 0x2703; + public static final int GL_LINEAR_MIPMAP_NEAREST = 0x2701; + public static final int GL_LINES = 0x0001; + public static final int GL_LUMINANCE = 0x1909; + public static final int GL_LUMINANCE_ALPHA = 0x190A; + public static final int GL_MAX_ELEMENTS_INDICES = 0x80E9; + public static final int GL_MAX_ELEMENTS_VERTICES = 0x80E8; + public static final int GL_MAX_LIGHTS = 0x0D31; + public static final int GL_MAX_MODELVIEW_STACK_DEPTH = 0x0D36; + public static final int GL_MAX_PROJECTION_STACK_DEPTH = 0x0D38; + public static final int GL_MAX_TEXTURE_SIZE = 0x0D33; + public static final int GL_MAX_TEXTURE_STACK_DEPTH = 0x0D39; + public static final int GL_MAX_TEXTURE_UNITS = 0x84E2; + public static final int GL_MAX_VIEWPORT_DIMS = 0x0D3A; + public static final int GL_MODELVIEW = 0x1700; + public static final int GL_MODULATE = 0x2100; + public static final int GL_MULTISAMPLE = 0x809D; + public static final int GL_NAND = 0x150E; + public static final int GL_NEAREST = 0x2600; + public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; + public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; + public static final int GL_NEVER = 0x0200; + public static final int GL_NICEST = 0x1102; + public static final int GL_NO_ERROR = 0; + public static final int GL_NOOP = 0x1505; + public static final int GL_NOR = 0x1508; + public static final int GL_NORMAL_ARRAY = 0x8075; + public static final int GL_NORMALIZE = 0x0BA1; + public static final int GL_NOTEQUAL = 0x0205; + public static final int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2; + public static final int GL_ONE = 1; + public static final int GL_ONE_MINUS_DST_ALPHA = 0x0305; + public static final int GL_ONE_MINUS_DST_COLOR = 0x0307; + public static final int GL_ONE_MINUS_SRC_ALPHA = 0x0303; + public static final int GL_ONE_MINUS_SRC_COLOR = 0x0301; + public static final int GL_OR = 0x1507; + public static final int GL_OR_INVERTED = 0x150D; + public static final int GL_OR_REVERSE = 0x150B; + public static final int GL_OUT_OF_MEMORY = 0x0505; + public static final int GL_PACK_ALIGNMENT = 0x0D05; + public static final int GL_PALETTE4_R5_G6_B5_OES = 0x8B92; + public static final int GL_PALETTE4_RGB5_A1_OES = 0x8B94; + public static final int GL_PALETTE4_RGB8_OES = 0x8B90; + public static final int GL_PALETTE4_RGBA4_OES = 0x8B93; + public static final int GL_PALETTE4_RGBA8_OES = 0x8B91; + public static final int GL_PALETTE8_R5_G6_B5_OES = 0x8B97; + public static final int GL_PALETTE8_RGB5_A1_OES = 0x8B99; + public static final int GL_PALETTE8_RGB8_OES = 0x8B95; + public static final int GL_PALETTE8_RGBA4_OES = 0x8B98; + public static final int GL_PALETTE8_RGBA8_OES = 0x8B96; + public static final int GL_PERSPECTIVE_CORRECTION_HINT = 0x0C50; + public static final int GL_POINT_SMOOTH = 0x0B10; + public static final int GL_POINT_SMOOTH_HINT = 0x0C51; + public static final int GL_POINTS = 0x0000; + public static final int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; + public static final int GL_POINT_SIZE = 0x0B11; + public static final int GL_POLYGON_OFFSET_FILL = 0x8037; + public static final int GL_POLYGON_SMOOTH_HINT = 0x0C53; + public static final int GL_POSITION = 0x1203; + public static final int GL_PROJECTION = 0x1701; + public static final int GL_QUADRATIC_ATTENUATION = 0x1209; + public static final int GL_RED_BITS = 0x0D52; + public static final int GL_RENDERER = 0x1F01; + public static final int GL_REPEAT = 0x2901; + public static final int GL_REPLACE = 0x1E01; + public static final int GL_RESCALE_NORMAL = 0x803A; + public static final int GL_RGB = 0x1907; + public static final int GL_RGBA = 0x1908; + public static final int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E; + public static final int GL_SAMPLE_ALPHA_TO_ONE = 0x809F; + public static final int GL_SAMPLE_COVERAGE = 0x80A0; + public static final int GL_SCISSOR_TEST = 0x0C11; + public static final int GL_SET = 0x150F; + public static final int GL_SHININESS = 0x1601; + public static final int GL_SHORT = 0x1402; + public static final int GL_SMOOTH = 0x1D01; + public static final int GL_SMOOTH_LINE_WIDTH_RANGE = 0x0B22; + public static final int GL_SMOOTH_POINT_SIZE_RANGE = 0x0B12; + public static final int GL_SPECULAR = 0x1202; + public static final int GL_SPOT_CUTOFF = 0x1206; + public static final int GL_SPOT_DIRECTION = 0x1204; + public static final int GL_SPOT_EXPONENT = 0x1205; + public static final int GL_SRC_ALPHA = 0x0302; + public static final int GL_SRC_ALPHA_SATURATE = 0x0308; + public static final int GL_SRC_COLOR = 0x0300; + public static final int GL_STACK_OVERFLOW = 0x0503; + public static final int GL_STACK_UNDERFLOW = 0x0504; + public static final int GL_STENCIL_BITS = 0x0D57; + public static final int GL_STENCIL_BUFFER_BIT = 0x0400; + public static final int GL_STENCIL_TEST = 0x0B90; + public static final int GL_SUBPIXEL_BITS = 0x0D50; + public static final int GL_TEXTURE = 0x1702; + public static final int GL_TEXTURE_2D = 0x0DE1; + public static final int GL_TEXTURE_COORD_ARRAY = 0x8078; + public static final int GL_TEXTURE_ENV = 0x2300; + public static final int GL_TEXTURE_ENV_COLOR = 0x2201; + public static final int GL_TEXTURE_ENV_MODE = 0x2200; + public static final int GL_TEXTURE_MAG_FILTER = 0x2800; + public static final int GL_TEXTURE_MIN_FILTER = 0x2801; + public static final int GL_TEXTURE_WRAP_S = 0x2802; + public static final int GL_TEXTURE_WRAP_T = 0x2803; + public static final int GL_TEXTURE0 = 0x84C0; + public static final int GL_TEXTURE1 = 0x84C1; + public static final int GL_TEXTURE2 = 0x84C2; + public static final int GL_TEXTURE3 = 0x84C3; + public static final int GL_TEXTURE4 = 0x84C4; + public static final int GL_TEXTURE5 = 0x84C5; + public static final int GL_TEXTURE6 = 0x84C6; + public static final int GL_TEXTURE7 = 0x84C7; + public static final int GL_TEXTURE8 = 0x84C8; + public static final int GL_TEXTURE9 = 0x84C9; + public static final int GL_TEXTURE10 = 0x84CA; + public static final int GL_TEXTURE11 = 0x84CB; + public static final int GL_TEXTURE12 = 0x84CC; + public static final int GL_TEXTURE13 = 0x84CD; + public static final int GL_TEXTURE14 = 0x84CE; + public static final int GL_TEXTURE15 = 0x84CF; + public static final int GL_TEXTURE16 = 0x84D0; + public static final int GL_TEXTURE17 = 0x84D1; + public static final int GL_TEXTURE18 = 0x84D2; + public static final int GL_TEXTURE19 = 0x84D3; + public static final int GL_TEXTURE20 = 0x84D4; + public static final int GL_TEXTURE21 = 0x84D5; + public static final int GL_TEXTURE22 = 0x84D6; + public static final int GL_TEXTURE23 = 0x84D7; + public static final int GL_TEXTURE24 = 0x84D8; + public static final int GL_TEXTURE25 = 0x84D9; + public static final int GL_TEXTURE26 = 0x84DA; + public static final int GL_TEXTURE27 = 0x84DB; + public static final int GL_TEXTURE28 = 0x84DC; + public static final int GL_TEXTURE29 = 0x84DD; + public static final int GL_TEXTURE30 = 0x84DE; + public static final int GL_TEXTURE31 = 0x84DF; + public static final int GL_TRIANGLE_FAN = 0x0006; + public static final int GL_TRIANGLE_STRIP = 0x0005; + public static final int GL_TRIANGLES = 0x0004; + public static final int GL_TRUE = 1; + public static final int GL_UNPACK_ALIGNMENT = 0x0CF5; + public static final int GL_UNSIGNED_BYTE = 0x1401; + public static final int GL_UNSIGNED_SHORT = 0x1403; + public static final int GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033; + public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; + public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; + public static final int GL_VENDOR = 0x1F00; + public static final int GL_VERSION = 0x1F02; + public static final int GL_VERTEX_ARRAY = 0x8074; + public static final int GL_XOR = 0x1506; + public static final int GL_ZERO = 0; + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + + private static Buffer _colorPointer; + private static Buffer _normalPointer; + private static Buffer _texCoordPointer; + private static Buffer _vertexPointer; + diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3948fd3a696f95ce59bc061d848f3715383df99c --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp @@ -0,0 +1,143 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +/* special calls implemented in Android's GLES wrapper used to more + * efficiently bound-check passed arrays */ +extern "C" { +GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, + const GLvoid *ptr, GLsizei count); +GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, + const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +} + +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. */ + +static 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); +} + +static int +getNumCompressedTextureFormats() { + int numCompressedTextureFormats = 0; + glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedTextureFormats); + return numCompressedTextureFormats; +} + +// -------------------------------------------------------------------------- + diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if new file mode 100644 index 0000000000000000000000000000000000000000..428ccee66626a1e82f6565c853bc41cd5d0dee84 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if @@ -0,0 +1,130 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +public class GLES11Ext { + public static final int GL_BLEND_EQUATION_RGB_OES = 0x8009; + public static final int GL_BLEND_EQUATION_ALPHA_OES = 0x883D; + public static final int GL_BLEND_DST_RGB_OES = 0x80C8; + public static final int GL_BLEND_SRC_RGB_OES = 0x80C9; + public static final int GL_BLEND_DST_ALPHA_OES = 0x80CA; + public static final int GL_BLEND_SRC_ALPHA_OES = 0x80CB; + public static final int GL_BLEND_EQUATION_OES = 0x8009; + public static final int GL_FUNC_ADD_OES = 0x8006; + public static final int GL_FUNC_SUBTRACT_OES = 0x800A; + public static final int GL_FUNC_REVERSE_SUBTRACT_OES = 0x800B; + public static final int GL_ETC1_RGB8_OES = 0x8D64; + public static final int GL_DEPTH_COMPONENT24_OES = 0x81A6; + public static final int GL_DEPTH_COMPONENT32_OES = 0x81A7; + public static final int GL_TEXTURE_CROP_RECT_OES = 0x8B9D; + public static final int GL_FIXED_OES = 0x140C; + public static final int GL_NONE_OES = 0; + public static final int GL_FRAMEBUFFER_OES = 0x8D40; + public static final int GL_RENDERBUFFER_OES = 0x8D41; + public static final int GL_RGBA4_OES = 0x8056; + public static final int GL_RGB5_A1_OES = 0x8057; + public static final int GL_RGB565_OES = 0x8D62; + public static final int GL_DEPTH_COMPONENT16_OES = 0x81A5; + public static final int GL_RENDERBUFFER_WIDTH_OES = 0x8D42; + public static final int GL_RENDERBUFFER_HEIGHT_OES = 0x8D43; + public static final int GL_RENDERBUFFER_INTERNAL_FORMAT_OES = 0x8D44; + public static final int GL_RENDERBUFFER_RED_SIZE_OES = 0x8D50; + public static final int GL_RENDERBUFFER_GREEN_SIZE_OES = 0x8D51; + public static final int GL_RENDERBUFFER_BLUE_SIZE_OES = 0x8D52; + public static final int GL_RENDERBUFFER_ALPHA_SIZE_OES = 0x8D53; + public static final int GL_RENDERBUFFER_DEPTH_SIZE_OES = 0x8D54; + public static final int GL_RENDERBUFFER_STENCIL_SIZE_OES = 0x8D55; + public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES = 0x8CD0; + public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES = 0x8CD1; + public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES = 0x8CD2; + public static final int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x8CD3; + public static final int GL_COLOR_ATTACHMENT0_OES = 0x8CE0; + public static final int GL_DEPTH_ATTACHMENT_OES = 0x8D00; + public static final int GL_STENCIL_ATTACHMENT_OES = 0x8D20; + public static final int GL_FRAMEBUFFER_COMPLETE_OES = 0x8CD5; + public static final int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES = 0x8CD6; + public static final int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES = 0x8CD7; + public static final int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES = 0x8CD9; + public static final int GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES = 0x8CDA; + public static final int GL_FRAMEBUFFER_UNSUPPORTED_OES = 0x8CDD; + public static final int GL_FRAMEBUFFER_BINDING_OES = 0x8CA6; + public static final int GL_RENDERBUFFER_BINDING_OES = 0x8CA7; + public static final int GL_MAX_RENDERBUFFER_SIZE_OES = 0x84E8; + public static final int GL_INVALID_FRAMEBUFFER_OPERATION_OES = 0x0506; + public static final int GL_WRITE_ONLY_OES = 0x88B9; + public static final int GL_BUFFER_ACCESS_OES = 0x88BB; + public static final int GL_BUFFER_MAPPED_OES = 0x88BC; + public static final int GL_BUFFER_MAP_POINTER_OES = 0x88BD; + public static final int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; + public static final int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; + public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; + public static final int GL_MAX_VERTEX_UNITS_OES = 0x86A4; + public static final int GL_MAX_PALETTE_MATRICES_OES = 0x8842; + public static final int GL_MATRIX_PALETTE_OES = 0x8840; + public static final int GL_MATRIX_INDEX_ARRAY_OES = 0x8844; + public static final int GL_WEIGHT_ARRAY_OES = 0x86AD; + public static final int GL_CURRENT_PALETTE_MATRIX_OES = 0x8843; + public static final int GL_MATRIX_INDEX_ARRAY_SIZE_OES = 0x8846; + public static final int GL_MATRIX_INDEX_ARRAY_TYPE_OES = 0x8847; + public static final int GL_MATRIX_INDEX_ARRAY_STRIDE_OES = 0x8848; + public static final int GL_MATRIX_INDEX_ARRAY_POINTER_OES = 0x8849; + public static final int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x8B9E; + public static final int GL_WEIGHT_ARRAY_SIZE_OES = 0x86AB; + public static final int GL_WEIGHT_ARRAY_TYPE_OES = 0x86A9; + public static final int GL_WEIGHT_ARRAY_STRIDE_OES = 0x86AA; + public static final int GL_WEIGHT_ARRAY_POINTER_OES = 0x86AC; + public static final int GL_WEIGHT_ARRAY_BUFFER_BINDING_OES = 0x889E; + public static final int GL_DEPTH_STENCIL_OES = 0x84F9; + public static final int GL_UNSIGNED_INT_24_8_OES = 0x84FA; + public static final int GL_DEPTH24_STENCIL8_OES = 0x88F0; + public static final int GL_RGB8_OES = 0x8051; + public static final int GL_RGBA8_OES = 0x8058; + public static final int GL_STENCIL_INDEX1_OES = 0x8D46; + public static final int GL_STENCIL_INDEX4_OES = 0x8D47; + public static final int GL_STENCIL_INDEX8_OES = 0x8D48; + public static final int GL_INCR_WRAP_OES = 0x8507; + public static final int GL_DECR_WRAP_OES = 0x8508; + public static final int GL_NORMAL_MAP_OES = 0x8511; + public static final int GL_REFLECTION_MAP_OES = 0x8512; + public static final int GL_TEXTURE_CUBE_MAP_OES = 0x8513; + public static final int GL_TEXTURE_BINDING_CUBE_MAP_OES = 0x8514; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES = 0x8515; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES = 0x8516; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES = 0x8517; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES = 0x8518; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES = 0x8519; + public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES = 0x851A; + public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES = 0x851C; + public static final int GL_TEXTURE_GEN_MODE_OES = 0x2500; + public static final int GL_TEXTURE_GEN_STR_OES = 0x8D60; + public static final int GL_MIRRORED_REPEAT_OES = 0x8370; + public static final int GL_3DC_X_AMD = 0x87F9; + public static final int GL_3DC_XY_AMD = 0x87FA; + public static final int GL_ATC_RGB_AMD = 0x8C92; + public static final int GL_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93; + public static final int GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE; + public static final int GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; + public static final int GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; + public static final int GL_BGRA = 0x80E1; + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + \ No newline at end of file diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..294d1ce82e72b83f63fa2aaf61becdb001415613 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp @@ -0,0 +1,125 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +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. */ + +static 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/gles11/GLES11Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES11Header.java-if new file mode 100644 index 0000000000000000000000000000000000000000..26f466fae2e1ec5bef674dd41e75b95d127d3fde --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES11Header.java-if @@ -0,0 +1,151 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +package android.opengl; + +import java.nio.Buffer; + +public class GLES11 extends GLES10 { + public static final int GL_ACTIVE_TEXTURE = 0x84E0; + public static final int GL_ADD_SIGNED = 0x8574; + public static final int GL_ALPHA_SCALE = 0x0D1C; + public static final int GL_ALPHA_TEST_FUNC = 0x0BC1; + public static final int GL_ALPHA_TEST_REF = 0x0BC2; + public static final int GL_ARRAY_BUFFER = 0x8892; + public static final int GL_ARRAY_BUFFER_BINDING = 0x8894; + public static final int GL_BLEND_DST = 0x0BE0; + public static final int GL_BLEND_SRC = 0x0BE1; + public static final int GL_BUFFER_ACCESS = 0x88BB; + public static final int GL_BUFFER_SIZE = 0x8764; + public static final int GL_BUFFER_USAGE = 0x8765; + public static final int GL_CLIENT_ACTIVE_TEXTURE = 0x84E1; + public static final int GL_CLIP_PLANE0 = 0x3000; + public static final int GL_CLIP_PLANE1 = 0x3001; + public static final int GL_CLIP_PLANE2 = 0x3002; + public static final int GL_CLIP_PLANE3 = 0x3003; + public static final int GL_CLIP_PLANE4 = 0x3004; + public static final int GL_CLIP_PLANE5 = 0x3005; + public static final int GL_COLOR_ARRAY_BUFFER_BINDING = 0x8898; + public static final int GL_COLOR_ARRAY_POINTER = 0x8090; + public static final int GL_COLOR_ARRAY_SIZE = 0x8081; + public static final int GL_COLOR_ARRAY_STRIDE = 0x8083; + public static final int GL_COLOR_ARRAY_TYPE = 0x8082; + public static final int GL_COLOR_CLEAR_VALUE = 0x0C22; + public static final int GL_COLOR_WRITEMASK = 0x0C23; + public static final int GL_COMBINE = 0x8570; + public static final int GL_COMBINE_ALPHA = 0x8572; + public static final int GL_COMBINE_RGB = 0x8571; + public static final int GL_CONSTANT = 0x8576; + public static final int GL_COORD_REPLACE_OES = 0x8862; + public static final int GL_CULL_FACE_MODE = 0x0B45; + public static final int GL_CURRENT_COLOR = 0x0B00; + public static final int GL_CURRENT_NORMAL = 0x0B02; + public static final int GL_CURRENT_TEXTURE_COORDS = 0x0B03; + public static final int GL_DEPTH_CLEAR_VALUE = 0x0B73; + public static final int GL_DEPTH_FUNC = 0x0B74; + public static final int GL_DEPTH_RANGE = 0x0B70; + public static final int GL_DEPTH_WRITEMASK = 0x0B72; + public static final int GL_DOT3_RGB = 0x86AE; + public static final int GL_DOT3_RGBA = 0x86AF; + public static final int GL_DYNAMIC_DRAW = 0x88E8; + public static final int GL_ELEMENT_ARRAY_BUFFER = 0x8893; + public static final int GL_ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; + public static final int GL_FRONT_FACE = 0x0B46; + public static final int GL_GENERATE_MIPMAP = 0x8191; + public static final int GL_GENERATE_MIPMAP_HINT = 0x8192; + public static final int GL_INTERPOLATE = 0x8575; + public static final int GL_LINE_WIDTH = 0x0B21; + public static final int GL_LOGIC_OP_MODE = 0x0BF0; + public static final int GL_MATRIX_MODE = 0x0BA0; + public static final int GL_MAX_CLIP_PLANES = 0x0D32; + public static final int GL_MODELVIEW_MATRIX = 0x0BA6; + public static final int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; + public static final int GL_MODELVIEW_STACK_DEPTH = 0x0BA3; + public static final int GL_NORMAL_ARRAY_BUFFER_BINDING = 0x8897; + public static final int GL_NORMAL_ARRAY_POINTER = 0x808F; + public static final int GL_NORMAL_ARRAY_STRIDE = 0x807F; + public static final int GL_NORMAL_ARRAY_TYPE = 0x807E; + public static final int GL_OPERAND0_ALPHA = 0x8598; + public static final int GL_OPERAND0_RGB = 0x8590; + public static final int GL_OPERAND1_ALPHA = 0x8599; + public static final int GL_OPERAND1_RGB = 0x8591; + public static final int GL_OPERAND2_ALPHA = 0x859A; + public static final int GL_OPERAND2_RGB = 0x8592; + public static final int GL_POINT_DISTANCE_ATTENUATION = 0x8129; + public static final int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; + public static final int GL_POINT_SIZE = 0x0B11; + public static final int GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES = 0x8B9F; + public static final int GL_POINT_SIZE_ARRAY_OES = 0x8B9C; + public static final int GL_POINT_SIZE_ARRAY_POINTER_OES = 0x898C; + public static final int GL_POINT_SIZE_ARRAY_STRIDE_OES = 0x898B; + public static final int GL_POINT_SIZE_ARRAY_TYPE_OES = 0x898A; + public static final int GL_POINT_SIZE_MAX = 0x8127; + public static final int GL_POINT_SIZE_MIN = 0x8126; + public static final int GL_POINT_SPRITE_OES = 0x8861; + public static final int GL_POLYGON_OFFSET_FACTOR = 0x8038; + public static final int GL_POLYGON_OFFSET_UNITS = 0x2A00; + public static final int GL_PREVIOUS = 0x8578; + public static final int GL_PRIMARY_COLOR = 0x8577; + public static final int GL_PROJECTION_MATRIX = 0x0BA7; + public static final int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; + public static final int GL_PROJECTION_STACK_DEPTH = 0x0BA4; + public static final int GL_RGB_SCALE = 0x8573; + public static final int GL_SAMPLE_BUFFERS = 0x80A8; + public static final int GL_SAMPLE_COVERAGE_INVERT = 0x80AB; + public static final int GL_SAMPLE_COVERAGE_VALUE = 0x80AA; + public static final int GL_SAMPLES = 0x80A9; + public static final int GL_SCISSOR_BOX = 0x0C10; + public static final int GL_SHADE_MODEL = 0x0B54; + public static final int GL_SRC0_ALPHA = 0x8588; + public static final int GL_SRC0_RGB = 0x8580; + public static final int GL_SRC1_ALPHA = 0x8589; + public static final int GL_SRC1_RGB = 0x8581; + public static final int GL_SRC2_ALPHA = 0x858A; + public static final int GL_SRC2_RGB = 0x8582; + public static final int GL_STATIC_DRAW = 0x88E4; + public static final int GL_STENCIL_CLEAR_VALUE = 0x0B91; + public static final int GL_STENCIL_FAIL = 0x0B94; + public static final int GL_STENCIL_FUNC = 0x0B92; + public static final int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95; + public static final int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96; + public static final int GL_STENCIL_REF = 0x0B97; + public static final int GL_STENCIL_VALUE_MASK = 0x0B93; + public static final int GL_STENCIL_WRITEMASK = 0x0B98; + public static final int GL_SUBTRACT = 0x84E7; + public static final int GL_TEXTURE_BINDING_2D = 0x8069; + public static final int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 0x889A; + public static final int GL_TEXTURE_COORD_ARRAY_POINTER = 0x8092; + public static final int GL_TEXTURE_COORD_ARRAY_SIZE = 0x8088; + public static final int GL_TEXTURE_COORD_ARRAY_STRIDE = 0x808A; + public static final int GL_TEXTURE_COORD_ARRAY_TYPE = 0x8089; + public static final int GL_TEXTURE_MATRIX = 0x0BA8; + public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; + public static final int GL_TEXTURE_STACK_DEPTH = 0x0BA5; + public static final int GL_VERTEX_ARRAY_BUFFER_BINDING = 0x8896; + public static final int GL_VERTEX_ARRAY_POINTER = 0x808E; + public static final int GL_VERTEX_ARRAY_SIZE = 0x807A; + public static final int GL_VERTEX_ARRAY_STRIDE = 0x807C; + public static final int GL_VERTEX_ARRAY_TYPE = 0x807B; + public static final int GL_VIEWPORT = 0x0BA2; + public static final int GL_WRITE_ONLY = 0x88B9; + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..294d1ce82e72b83f63fa2aaf61becdb001415613 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp @@ -0,0 +1,125 @@ +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// This source file is automatically generated + +#include +#include + +#include +#include +#include + +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. */ + +static 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/glGetString.cpp b/opengl/tools/glgen/stubs/gles11/glGetString.cpp similarity index 93% rename from opengl/tools/glgen/stubs/glGetString.cpp rename to opengl/tools/glgen/stubs/gles11/glGetString.cpp index 22e12971778df6a4fd0d4333cc370478a1b938e1..a400859f771f66ac79548e0ba1e942082f0ab174 100644 --- a/opengl/tools/glgen/stubs/glGetString.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetString.cpp @@ -1,6 +1,7 @@ #include /* const GLubyte * glGetString ( GLenum name ) */ +static jstring android_glGetString (JNIEnv *_env, jobject _this, jint name) { diff --git a/opengl/tools/glgen/stubs/gles11/glGetString.java b/opengl/tools/glgen/stubs/gles11/glGetString.java new file mode 100644 index 0000000000000000000000000000000000000000..fba249b0db05415e29561fd433a652dab1245156 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetString.java @@ -0,0 +1,5 @@ + // C function const GLubyte * glGetString ( GLenum name ) + + public static native String glGetString( + int name + ); diff --git a/opengl/tools/glgen/stubs/gles11/glGetString.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetString.nativeReg new file mode 100644 index 0000000000000000000000000000000000000000..a4af31fe7f2de1b16a1216f6e0e8880acd5355d5 --- /dev/null +++ b/opengl/tools/glgen/stubs/gles11/glGetString.nativeReg @@ -0,0 +1 @@ +{"glGetString", "(I)Ljava/lang/String;", (void *) android_glGetString }, diff --git a/opengl/tools/glgen/stubs/GL10ExtHeader.java-if b/opengl/tools/glgen/stubs/jsr239/GL10ExtHeader.java-if similarity index 100% rename from opengl/tools/glgen/stubs/GL10ExtHeader.java-if rename to opengl/tools/glgen/stubs/jsr239/GL10ExtHeader.java-if diff --git a/opengl/tools/glgen/stubs/GL10Header.java-if b/opengl/tools/glgen/stubs/jsr239/GL10Header.java-if similarity index 100% rename from opengl/tools/glgen/stubs/GL10Header.java-if rename to opengl/tools/glgen/stubs/jsr239/GL10Header.java-if diff --git a/opengl/tools/glgen/stubs/GL11ExtHeader.java-if b/opengl/tools/glgen/stubs/jsr239/GL11ExtHeader.java-if similarity index 100% rename from opengl/tools/glgen/stubs/GL11ExtHeader.java-if rename to opengl/tools/glgen/stubs/jsr239/GL11ExtHeader.java-if diff --git a/opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if b/opengl/tools/glgen/stubs/jsr239/GL11ExtensionPackHeader.java-if similarity index 100% rename from opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if rename to opengl/tools/glgen/stubs/jsr239/GL11ExtensionPackHeader.java-if diff --git a/opengl/tools/glgen/stubs/GL11Header.java-if b/opengl/tools/glgen/stubs/jsr239/GL11Header.java-if similarity index 100% rename from opengl/tools/glgen/stubs/GL11Header.java-if rename to opengl/tools/glgen/stubs/jsr239/GL11Header.java-if diff --git a/opengl/tools/glgen/stubs/GL11ImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GL11ImplHeader.java-impl similarity index 100% rename from opengl/tools/glgen/stubs/GL11ImplHeader.java-impl rename to opengl/tools/glgen/stubs/jsr239/GL11ImplHeader.java-impl diff --git a/opengl/tools/glgen/stubs/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp similarity index 81% rename from opengl/tools/glgen/stubs/GLCHeader.cpp rename to opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index 6495686b2aad4a47ba6dcf1d7b5b352925228475..11c6087bf42a1436955e1d46d8e76d65736ad9be 100644 --- a/opengl/tools/glgen/stubs/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -21,11 +21,20 @@ #include #include - -#include - -#define _NUM_COMPRESSED_TEXTURE_FORMATS \ - (::android::OGLES_NUM_COMPRESSED_TEXTURE_FORMATS) +#include + +/* special calls implemented in Android's GLES wrapper used to more + * efficiently bound-check passed arrays */ +extern "C" { +GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride, + const GLvoid *ptr, GLsizei count); +GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride, + const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer, GLsizei count); +} static int initialized = 0; @@ -44,7 +53,7 @@ static jfieldID elementSizeShiftID; /* Cache method IDs each time the class is loaded. */ -void +static void nativeClassInitBuffer(JNIEnv *_env) { jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); @@ -66,7 +75,6 @@ nativeClassInitBuffer(JNIEnv *_env) _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { @@ -117,7 +125,6 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) return (void *) ((char *) data + offset); } - static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { @@ -125,5 +132,12 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) commit ? 0 : JNI_ABORT); } +static int +getNumCompressedTextureFormats() { + int numCompressedTextureFormats = 0; + glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedTextureFormats); + return numCompressedTextureFormats; +} + // -------------------------------------------------------------------------- diff --git a/opengl/tools/glgen/stubs/GLHeader.java-if b/opengl/tools/glgen/stubs/jsr239/GLHeader.java-if similarity index 100% rename from opengl/tools/glgen/stubs/GLHeader.java-if rename to opengl/tools/glgen/stubs/jsr239/GLHeader.java-if diff --git a/opengl/tools/glgen/stubs/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl similarity index 100% rename from opengl/tools/glgen/stubs/GLImplHeader.java-impl rename to opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl diff --git a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a400859f771f66ac79548e0ba1e942082f0ab174 --- /dev/null +++ b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp @@ -0,0 +1,11 @@ +#include + +/* const GLubyte * glGetString ( GLenum name ) */ +static +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/jsr239/glGetString.java-10-if similarity index 100% rename from opengl/tools/glgen/stubs/glGetString.java-10-if rename to opengl/tools/glgen/stubs/jsr239/glGetString.java-10-if diff --git a/opengl/tools/glgen/stubs/glGetString.java-if b/opengl/tools/glgen/stubs/jsr239/glGetString.java-if similarity index 100% rename from opengl/tools/glgen/stubs/glGetString.java-if rename to opengl/tools/glgen/stubs/jsr239/glGetString.java-if diff --git a/opengl/tools/glgen/stubs/glGetString.java-impl b/opengl/tools/glgen/stubs/jsr239/glGetString.java-impl similarity index 100% rename from opengl/tools/glgen/stubs/glGetString.java-impl rename to opengl/tools/glgen/stubs/jsr239/glGetString.java-impl diff --git a/opengl/tools/glgen/stubs/glGetString.nativeReg b/opengl/tools/glgen/stubs/jsr239/glGetString.nativeReg similarity index 100% rename from opengl/tools/glgen/stubs/glGetString.nativeReg rename to opengl/tools/glgen/stubs/jsr239/glGetString.nativeReg diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index d39934b73631f583340907cfe30013fa9a8adabc..b9d567c76169a3c5563dd050260c70532b2897cc 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -38,6 +38,7 @@ import android.util.Config; import android.util.Log; import android.util.Xml; import com.android.internal.util.XmlUtils; +import com.android.internal.telephony.RILConstants; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; @@ -175,7 +176,8 @@ class DatabaseHelper extends SQLiteOpenHelper { // Shortcuts, applications, folders db.execSQL("UPDATE favorites SET spanX=1, spanY=1 WHERE itemType<=0"); // Photo frames, clocks - db.execSQL("UPDATE favorites SET spanX=2, spanY=2 WHERE itemType=1000 or itemType=1002"); + db.execSQL( + "UPDATE favorites SET spanX=2, spanY=2 WHERE itemType=1000 or itemType=1002"); // Search boxes db.execSQL("UPDATE favorites SET spanX=4, spanY=1 WHERE itemType=1001"); db.setTransactionSuccessful(); @@ -582,6 +584,8 @@ class DatabaseHelper extends SQLiteOpenHelper { + " VALUES(?,?);"); Resources r = mContext.getResources(); + loadSetting(stmt, Settings.Secure.CURRENT_ACTIVE_PHONE, + RILConstants.CDMA_PHONE); loadBooleanSetting(stmt, Settings.System.DIM_SCREEN, R.bool.def_dim_screen); loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN, @@ -655,6 +659,18 @@ class DatabaseHelper extends SQLiteOpenHelper { loadSetting(stmt, Settings.Secure.WIFI_WATCHDOG_WATCH_LIST, wifiWatchList); } + // Set the preferred network mode to 0 = Global, CDMA default + loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, + RILConstants.PREFERRED_NETWORK_MODE); + + // Enable or disable Cell Broadcast SMS + loadSetting(stmt, Settings.Secure.CDMA_CELL_BROADCAST_SMS, + RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED); + + // Set the preferred cdma subscription to 0 = Subscription from RUIM, when available + loadSetting(stmt, Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION, + RILConstants.PREFERRED_CDMA_SUBSCRIPTION); + // Don't do this. The SystemServer will initialize ADB_ENABLED from a // persistent system property instead. //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0); @@ -691,3 +707,4 @@ class DatabaseHelper extends SQLiteOpenHelper { Float.toString(mContext.getResources().getFraction(resid, base, base))); } } + diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 333a450e0a80e2b68f1cc319114050a3a1770739..6f430c43c09ebf2e4713d7cc465c822cceb21021 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -244,6 +244,72 @@ public class SettingsProvider extends ContentProvider { return values.length; } + /* + * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED. + * This setting contains a list of the currently enabled location providers. + * But helper functions in android.providers.Settings can enable or disable + * a single provider by using a "+" or "-" prefix before the provider name. + */ + private boolean parseProviderList(Uri url, ContentValues initialValues) { + String value = initialValues.getAsString(Settings.Secure.VALUE); + String newProviders = null; + if (value != null && value.length() > 1) { + char prefix = value.charAt(0); + if (prefix == '+' || prefix == '-') { + // skip prefix + value = value.substring(1); + + // read list of enabled providers into "providers" + String providers = ""; + String[] columns = {Settings.Secure.VALUE}; + String where = Settings.Secure.NAME + "=\'" + Settings.Secure.LOCATION_PROVIDERS_ALLOWED + "\'"; + Cursor cursor = query(url, columns, where, null, null); + if (cursor != null && cursor.getCount() == 1) { + try { + cursor.moveToFirst(); + providers = cursor.getString(0); + } finally { + cursor.close(); + } + } + + int index = providers.indexOf(value); + int end = index + value.length(); + // check for commas to avoid matching on partial string + if (index > 0 && providers.charAt(index - 1) != ',') index = -1; + if (end < providers.length() && providers.charAt(end) != ',') index = -1; + + if (prefix == '+' && index < 0) { + // append the provider to the list if not present + if (providers.length() == 0) { + newProviders = value; + } else { + newProviders = providers + ',' + value; + } + } else if (prefix == '-' && index >= 0) { + // remove the provider from the list if present + // remove leading and trailing commas + if (index > 0) index--; + if (end < providers.length()) end++; + + newProviders = providers.substring(0, index); + if (end < providers.length()) { + newProviders += providers.substring(end); + } + } else { + // nothing changed, so no need to update the database + return false; + } + + if (newProviders != null) { + initialValues.put(Settings.Secure.VALUE, newProviders); + } + } + } + + return true; + } + @Override public Uri insert(Uri url, ContentValues initialValues) { SqlArguments args = new SqlArguments(url); @@ -252,6 +318,13 @@ public class SettingsProvider extends ContentProvider { } checkWritePermissions(args); + // Special case LOCATION_PROVIDERS_ALLOWED. + // Support enabling/disabling a single provider (using "+" or "-" prefix) + String name = initialValues.getAsString(Settings.Secure.NAME); + if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) { + if (!parseProviderList(url, initialValues)) return null; + } + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final long rowId = db.insert(args.table, null, initialValues); if (rowId <= 0) return null; diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java index df599c7cfa1d3965545b6e60f743aa7eef2cb8f7..8b3bedf28a7a22944b7cfefcd9d04c4fd5fdfb04 100644 --- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java +++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java @@ -9,7 +9,6 @@ import android.util.Log; import android.util.Config; import android.util.EventLog; import android.app.IntentService; -import android.provider.Sync; import android.provider.SubscribedFeeds; import android.provider.SyncConstValue; import android.database.Cursor; @@ -17,7 +16,7 @@ import android.database.sqlite.SQLiteFullException; import android.app.AlarmManager; import android.app.PendingIntent; import android.os.Bundle; -import android.os.Debug; +import android.os.RemoteException; import android.text.TextUtils; import android.net.Uri; @@ -105,10 +104,6 @@ public class SubscribedFeedsIntentService extends IntentService { private void handleTickle(Context context, String account, String feed) { Cursor c = null; - Sync.Settings.QueryMap syncSettings = - new Sync.Settings.QueryMap(context.getContentResolver(), - false /* don't keep updated */, - null /* not needed since keep updated is false */); final String where = SubscribedFeeds.Feeds._SYNC_ACCOUNT + "= ? " + "and " + SubscribedFeeds.Feeds.FEED + "= ?"; try { @@ -124,9 +119,14 @@ public class SubscribedFeedsIntentService extends IntentService { String authority = c.getString(c.getColumnIndexOrThrow( SubscribedFeeds.Feeds.AUTHORITY)); EventLog.writeEvent(LOG_TICKLE, authority); - if (!syncSettings.getSyncProviderAutomatically(authority)) { - Log.d(TAG, "supressing tickle since provider " + authority - + " is configured to not sync automatically"); + try { + if (!ContentResolver.getContentService() + .getSyncProviderAutomatically(authority)) { + Log.d(TAG, "supressing tickle since provider " + authority + + " is configured to not sync automatically"); + continue; + } + } catch (RemoteException e) { continue; } Uri uri = Uri.parse("content://" + authority); @@ -137,7 +137,6 @@ public class SubscribedFeedsIntentService extends IntentService { } } finally { if (c != null) c.deactivate(); - syncSettings.close(); } } diff --git a/preloaded-classes b/preloaded-classes index e3197b415ea7543ed4dacb021e582985da16a49b..0520e4106082cb093a36488dfa60c9da4242da67 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -76,8 +76,6 @@ android.content.ContentQueryMap android.content.ContentQueryMap$1 android.content.ContentResolver android.content.ContentResolver$CursorWrapperInner -android.content.ContentServiceNative -android.content.ContentServiceProxy android.content.ContentValues android.content.Context android.content.ContextWrapper @@ -85,6 +83,8 @@ android.content.DialogInterface android.content.DialogInterface$OnCancelListener android.content.DialogInterface$OnDismissListener android.content.IContentProvider +android.content.IContentService +android.content.IContentService$Stub android.content.Intent android.content.Intent$1 android.content.IntentFilter @@ -300,8 +300,8 @@ android.telephony.PhoneNumberUtils android.telephony.PhoneStateListener android.telephony.ServiceState android.telephony.TelephonyManager -android.telephony.gsm.SmsManager -android.telephony.gsm.SmsMessage +android.telephony.SmsManager +android.telephony.SmsMessage android.text.AutoText android.text.BoringLayout android.text.BoringLayout$Metrics @@ -453,17 +453,22 @@ android.view.animation.Transformation android.view.inputmethod.BaseInputConnection android.view.inputmethod.CompletionInfo android.view.inputmethod.CompletionInfo$1 + android.view.inputmethod.EditorInfo android.view.inputmethod.EditorInfo$1 + android.view.inputmethod.ExtractedText android.view.inputmethod.ExtractedText$1 + android.view.inputmethod.ExtractedTextRequest android.view.inputmethod.ExtractedTextRequest$1 + android.view.inputmethod.InputBinding android.view.inputmethod.InputBinding$1 android.view.inputmethod.InputConnection android.view.inputmethod.InputMethod android.view.inputmethod.InputMethod$SessionCallback + android.view.inputmethod.InputMethodInfo android.view.inputmethod.InputMethodInfo$1 android.view.inputmethod.InputMethodManager @@ -471,6 +476,7 @@ android.view.inputmethod.InputMethodManager$1 android.view.inputmethod.InputMethodManager$2 android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper android.view.inputmethod.InputMethodManager$H + android.view.inputmethod.InputMethodSession android.view.inputmethod.InputMethodSession$EventCallback android.webkit.BrowserFrame @@ -629,50 +635,59 @@ com.android.internal.telephony.Phone$State com.android.internal.telephony.Phone$SuppService com.android.internal.telephony.PhoneBase com.android.internal.telephony.PhoneStateIntentReceiver -com.android.internal.telephony.SimCard$State -com.android.internal.telephony.gsm.BaseCommands -com.android.internal.telephony.gsm.CallForwardInfo -com.android.internal.telephony.gsm.CommandsInterface -com.android.internal.telephony.gsm.DriverCall -com.android.internal.telephony.gsm.DriverCall$State -com.android.internal.telephony.gsm.GSMConnection +com.android.internal.telephony.IccCard$State +com.android.internal.telephony.BaseCommands +com.android.internal.telephony.CallForwardInfo +com.android.internal.telephony.CommandsInterface +com.android.internal.telephony.DriverCall +com.android.internal.telephony.DriverCall$State +com.android.internal.telephony.gsm.GsmConnection com.android.internal.telephony.gsm.GSMPhone -com.android.internal.telephony.gsm.GsmAlphabet +com.android.internal.telephony.GsmAlphabet com.android.internal.telephony.gsm.GsmMmiCode -com.android.internal.telephony.gsm.GsmSimCard -com.android.internal.telephony.gsm.ISms$Stub -com.android.internal.telephony.gsm.PdpConnection$PdpFailCause -com.android.internal.telephony.gsm.RIL -com.android.internal.telephony.gsm.ServiceStateTracker +com.android.internal.telephony.gsm.SimCard +com.android.internal.telephony.ISms$Stub +com.android.internal.telephony.RIL +com.android.internal.telephony.ServiceStateTracker + com.android.internal.telephony.gsm.stk.ComprehensionTlvTag com.android.internal.telephony.gsm.stk.ResultCode com.android.internal.util.FastXmlSerializer com.android.internal.view.IInputConnectionWrapper com.android.internal.view.IInputConnectionWrapper$MyHandler com.android.internal.view.IInputConnectionWrapper$SomeArgs + com.android.internal.view.IInputContext com.android.internal.view.IInputContext$Stub com.android.internal.view.IInputContext$Stub$Proxy + com.android.internal.view.IInputContextCallback com.android.internal.view.IInputContextCallback$Stub com.android.internal.view.IInputContextCallback$Stub$Proxy + com.android.internal.view.IInputMethod com.android.internal.view.IInputMethod$Stub com.android.internal.view.IInputMethod$Stub$Proxy + com.android.internal.view.IInputMethodCallback com.android.internal.view.IInputMethodCallback$Stub com.android.internal.view.IInputMethodCallback$Stub$Proxy + com.android.internal.view.IInputMethodClient com.android.internal.view.IInputMethodClient$Stub com.android.internal.view.IInputMethodClient$Stub$Proxy + com.android.internal.view.IInputMethodManager com.android.internal.view.IInputMethodManager$Stub com.android.internal.view.IInputMethodManager$Stub$Proxy + com.android.internal.view.IInputMethodSession com.android.internal.view.IInputMethodSession$Stub com.android.internal.view.IInputMethodSession$Stub$Proxy + com.android.internal.view.InputBindResult com.android.internal.view.InputBindResult$1 + com.android.internal.view.InputConnectionWrapper com.android.internal.view.InputConnectionWrapper$InputContextCallback com.android.internal.view.menu.ExpandedMenuView @@ -1165,3 +1180,4 @@ org.xml.sax.helpers.NewInstance org.xmlpull.v1.XmlPullParserFactory org.xmlpull.v1.sax2.Driver sun.misc.Unsafe + diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index d66c6e5e120450883bd6d7fa6205d6707265d90e..9c4ace1e8e4f19c85aa7e14a7acf94652075ded7 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -413,41 +413,45 @@ class AlarmManagerService extends IAlarmManager.Stub { synchronized (mLock) { pw.println("Current Alarm Manager state:"); - if (mRtcWakeupAlarms.size() > 0) { + if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) { pw.println(" "); - pw.println(" Realtime wakeup alarms that are scheduled:"); - dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP"); - } - if (mRtcAlarms.size() > 0) { - pw.println(" "); - pw.println(" Realtime alarms that are scheduled:"); - dumpAlarmList(pw, mRtcAlarms, " ", "RTC"); - } - if (mElapsedRealtimeWakeupAlarms.size() > 0) { - pw.println(" "); - pw.println(" Elapsed realtime wakeup alarms that are scheduled:"); - dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_REALTIME_WAKEUP"); + pw.print(" Realtime wakeup (now="); + pw.print(System.currentTimeMillis()); pw.println("):"); + if (mRtcWakeupAlarms.size() > 0) { + dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP"); + } + if (mRtcAlarms.size() > 0) { + dumpAlarmList(pw, mRtcAlarms, " ", "RTC"); + } } - if (mElapsedRealtimeAlarms.size() > 0) { + if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) { pw.println(" "); - pw.println(" Elapsed realtime alarms that are scheduled:"); - dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED_REALTIME"); + pw.print(" Elapsed realtime wakeup (now="); + pw.print(SystemClock.elapsedRealtime()); pw.println("):"); + if (mElapsedRealtimeWakeupAlarms.size() > 0) { + dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP"); + } + if (mElapsedRealtimeAlarms.size() > 0) { + dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED"); + } } pw.println(" "); - pw.println(" Broadcast ref count: " + mBroadcastRefCount); + pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); pw.println(" "); pw.println(" Alarm Stats:"); for (Map.Entry be : mBroadcastStats.entrySet()) { BroadcastStats bs = be.getValue(); - pw.println(" " + be.getKey()); - pw.println(" " + bs.aggregateTime + "ms running, " - + bs.numWakeup + " wakeups"); + pw.print(" "); pw.println(be.getKey()); + pw.print(" "); pw.print(bs.aggregateTime); + pw.print("ms running, "); pw.print(bs.numWakeup); + pw.println(" wakeups"); for (Map.Entry fe : bs.filterStats.entrySet()) { - pw.println(" " + fe.getValue().count + " alarms: " - + fe.getKey().getIntent()); + pw.print(" "); pw.print(fe.getValue().count); + pw.print(" alarms: "); + pw.println(fe.getKey().getIntent().toShortString(true, false)); } } } @@ -456,7 +460,8 @@ class AlarmManagerService extends IAlarmManager.Stub { private static final void dumpAlarmList(PrintWriter pw, ArrayList list, String prefix, String label) { for (int i=list.size()-1; i>=0; i--) { Alarm a = list.get(i); - pw.println(prefix + label + " #" + i + ":"); + pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); + pw.print(": "); pw.println(a); a.dump(pw, prefix + " "); } } @@ -561,18 +566,24 @@ class AlarmManagerService extends IAlarmManager.Stub { @Override public String toString() { - return "Alarm{" - + Integer.toHexString(System.identityHashCode(this)) - + " type " + type + " " + operation.getTargetPackage() + "}"; + StringBuilder sb = new StringBuilder(128); + sb.append("Alarm{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" type "); + sb.append(type); + sb.append(" "); + sb.append(operation.getTargetPackage()); + sb.append('}'); + return sb.toString(); } public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "type=" + type + " when=" + when - + " repeatInterval=" + repeatInterval - + " count=" + count); - pw.println(prefix + "operation=" + operation); + pw.print(prefix); pw.print("type="); pw.print(type); + pw.print(" when="); pw.print(when); + pw.print(" repeatInterval="); pw.print(repeatInterval); + pw.print(" count="); pw.println(count); + pw.print(prefix); pw.print("operation="); pw.println(operation); } } diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index de5d0acf7482f110a0695d860a09ec829b6362de..c50ae94676ac48de589e07697bf92161f483fa3f 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -35,6 +35,7 @@ import android.content.res.XmlResourceParser; import android.net.Uri; import android.os.Binder; import android.os.Bundle; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.util.AttributeSet; @@ -151,34 +152,57 @@ class AppWidgetService extends IAppWidgetService.Stub synchronized (mAppWidgetIds) { int N = mInstalledProviders.size(); - pw.println("Providers: (size=" + N + ")"); + pw.println("Providers:"); for (int i=0; i> mBackupParticipants + = new SparseArray>(); + // set of backup services that have pending changes + private class BackupRequest { + public ServiceInfo service; + public boolean fullBackup; + + BackupRequest(ServiceInfo svc, boolean isFull) { + service = svc; + fullBackup = isFull; + } + } + // Backups that we haven't started yet. + private HashMap mPendingBackups = new HashMap(); + // Backups that we have started. These are separate to prevent starvation + // if an app keeps re-enqueuing itself. + private ArrayList mBackupQueue; + private final Object mQueueLock = new Object(); + + private File mStateDir; + private File mDataDir; + + public BackupManagerService(Context context) { + mContext = context; + mPackageManager = context.getPackageManager(); + + // Set up our bookkeeping + mStateDir = new File(Environment.getDataDirectory(), "backup"); + mStateDir.mkdirs(); + mDataDir = Environment.getDownloadCacheDirectory(); + + // Build our mapping of uid to backup client services + synchronized (mBackupParticipants) { + addPackageParticipantsLocked(null); + } + + // Register for broadcasts about package install, etc., so we can + // update the provider list. + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addDataScheme("package"); + mContext.registerReceiver(mBroadcastReceiver, filter); + } + + // ----- Track installation/removal of packages ----- + BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (DEBUG) Log.d(TAG, "Received broadcast " + intent); + + Uri uri = intent.getData(); + if (uri == null) { + return; + } + String pkgName = uri.getSchemeSpecificPart(); + if (pkgName == null) { + return; + } + + String action = intent.getAction(); + if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + synchronized (mBackupParticipants) { + Bundle extras = intent.getExtras(); + if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { + // The package was just upgraded + updatePackageParticipantsLocked(pkgName); + } else { + // The package was just added + addPackageParticipantsLocked(pkgName); + } + } + } + else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + Bundle extras = intent.getExtras(); + if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { + // The package is being updated. We'll receive a PACKAGE_ADDED shortly. + } else { + synchronized (mBackupParticipants) { + removePackageParticipantsLocked(pkgName); + } + } + } + } + }; + + // ----- Run the actual backup process asynchronously ----- + + private class BackupHandler extends Handler implements ServiceConnection { + public void handleMessage(Message msg) { + + switch (msg.what) { + case MSG_RUN_BACKUP: + // snapshot the pending-backup set and work on that + synchronized (mQueueLock) { + mBackupQueue = new ArrayList(); + for (BackupRequest b: mPendingBackups.values()) { + mBackupQueue.add(b); + } + mPendingBackups = new HashMap(); + // !!! TODO: start a new backup-queue journal file too + // WARNING: If we crash after this line, anything in mPendingBackups will + // be lost. FIX THIS. + } + startOneService(); + break; + } + } + + public void onServiceConnected(ComponentName name, IBinder service) { + Log.d(TAG, "onServiceConnected name=" + name + " service=" + service); + IBackupService bs = IBackupService.Stub.asInterface(service); + processOneBackup(name, bs); + } + + public void onServiceDisconnected(ComponentName name) { + // TODO: handle backup being interrupted + } + } + + void startOneService() { + // Loop until we find someone to start or the queue empties out. + Intent intent = new Intent(BackupService.SERVICE_ACTION); + while (true) { + BackupRequest request; + synchronized (mQueueLock) { + int queueSize = mBackupQueue.size(); + if (queueSize == 0) { + mBackupQueue = null; + // TODO: Anything else to do here? + return; + } + request = mBackupQueue.get(0); + // Take it off the queue when we're done. + } + + intent.setClassName(request.service.packageName, request.service.name); + Log.d(TAG, "binding to " + intent); + try { + if (mContext.bindService(intent, mBackupHandler, Context.BIND_AUTO_CREATE)) { + Log.d(TAG, "awaiting service object for " + intent); + // success + return; + } + } catch (SecurityException ex) { + // Try for the next one. + Log.d(TAG, "error in bind", ex); + } + } + } + + void processOneBackup(ComponentName name, IBackupService bs) { + try { + Log.d(TAG, "processOneBackup doBackup() on " + name); + + BackupRequest request; + synchronized (mQueueLock) { + if (mBackupQueue == null) { + Log.d(TAG, "mBackupQueue is null. WHY?"); + } + request = mBackupQueue.get(0); + } + + // !!! TODO right now these naming schemes limit applications to + // one backup service per package + File savedStateName = new File(mStateDir, request.service.packageName); + File backupDataName = new File(mDataDir, request.service.packageName + ".data"); + File newStateName = new File(mStateDir, request.service.packageName + ".new"); + + // In a full backup, we pass a null ParcelFileDescriptor as + // the saved-state "file" + ParcelFileDescriptor savedState = (request.fullBackup) ? null + : ParcelFileDescriptor.open(savedStateName, + ParcelFileDescriptor.MODE_READ_ONLY | + ParcelFileDescriptor.MODE_CREATE); + + backupDataName.delete(); + ParcelFileDescriptor backupData = + ParcelFileDescriptor.open(backupDataName, + ParcelFileDescriptor.MODE_READ_WRITE | + ParcelFileDescriptor.MODE_CREATE); + + newStateName.delete(); + ParcelFileDescriptor newState = + ParcelFileDescriptor.open(newStateName, + ParcelFileDescriptor.MODE_READ_WRITE | + ParcelFileDescriptor.MODE_CREATE); + + // Run the target's backup pass + try { + // TODO: Make this oneway + bs.doBackup(savedState, backupData, newState); + } finally { + if (savedState != null) { + savedState.close(); + } + backupData.close(); + newState.close(); + } + + // !!! TODO: Now propagate the newly-backed-up data to the transport + + // !!! TODO: After successful transport, delete the now-stale data + // and juggle the files so that next time the new state is passed + backupDataName.delete(); + newStateName.renameTo(savedStateName); + + } catch (FileNotFoundException fnf) { + Log.d(TAG, "File not found on backup: "); + fnf.printStackTrace(); + } catch (RemoteException e) { + Log.d(TAG, "Remote target " + name + " threw during backup:"); + e.printStackTrace(); + } catch (Exception e) { + Log.w(TAG, "Final exception guard in backup: "); + e.printStackTrace(); + } + synchronized (mQueueLock) { + mBackupQueue.remove(0); + } + mContext.unbindService(mBackupHandler); + } + + // Add the backup services in the given package to our set of known backup participants. + // If 'packageName' is null, adds all backup services in the system. + void addPackageParticipantsLocked(String packageName) { + List services = mPackageManager.queryIntentServices( + new Intent(BackupService.SERVICE_ACTION), 0); + addPackageParticipantsLockedInner(packageName, services); + } + + private void addPackageParticipantsLockedInner(String packageName, List services) { + for (ResolveInfo ri : services) { + if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) { + int uid = ri.serviceInfo.applicationInfo.uid; + HashSet set = mBackupParticipants.get(uid); + if (set == null) { + set = new HashSet(); + mBackupParticipants.put(uid, set); + } + if (DEBUG) { + Log.v(TAG, "Adding " + services.size() + " backup participants:"); + for (ResolveInfo svc : services) { + Log.v(TAG, " " + svc + " : " + svc.filter); + } + } + + set.add(ri.serviceInfo); + } + } + } + + // Remove the given package's backup services from our known active set. If + // 'packageName' is null, *all* backup services will be removed. + void removePackageParticipantsLocked(String packageName) { + List services = mPackageManager.queryIntentServices( + new Intent(BackupService.SERVICE_ACTION), 0); + removePackageParticipantsLockedInner(packageName, services); + } + + private void removePackageParticipantsLockedInner(String packageName, + List services) { + for (ResolveInfo ri : services) { + if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) { + int uid = ri.serviceInfo.applicationInfo.uid; + HashSet set = mBackupParticipants.get(uid); + if (set != null) { + set.remove(ri.serviceInfo); + if (set.size() == 0) { + mBackupParticipants.put(uid, null); + } + } + } + } + } + + // Reset the given package's known backup participants. Unlike add/remove, the update + // action cannot be passed a null package name. + void updatePackageParticipantsLocked(String packageName) { + if (packageName == null) { + Log.e(TAG, "updatePackageParticipants called with null package name"); + return; + } + + // brute force but small code size + List services = mPackageManager.queryIntentServices( + new Intent(BackupService.SERVICE_ACTION), 0); + removePackageParticipantsLockedInner(packageName, services); + addPackageParticipantsLockedInner(packageName, services); + } + + // ----- IBackupManager binder interface ----- + + public void dataChanged(String packageName) throws RemoteException { + // Record that we need a backup pass for the caller. Since multiple callers + // may share a uid, we need to note all candidates within that uid and schedule + // a backup pass for each of them. + + Log.d(TAG, "dataChanged packageName=" + packageName); + + HashSet targets = mBackupParticipants.get(Binder.getCallingUid()); + Log.d(TAG, "targets=" + targets); + if (targets != null) { + synchronized (mQueueLock) { + // Note that this client has made data changes that need to be backed up + for (ServiceInfo service : targets) { + // validate the caller-supplied package name against the known set of + // packages associated with this uid + if (service.packageName.equals(packageName)) { + // Add the caller to the set of pending backups. If there is + // one already there, then overwrite it, but no harm done. + mPendingBackups.put(new ComponentName(service.packageName, service.name), + new BackupRequest(service, true)); + // !!! TODO: write to the pending-backup journal file in case of crash + } + } + + Log.d(TAG, "Scheduling backup for " + mPendingBackups.size() + " participants"); + // Schedule a backup pass in a few minutes. As backup-eligible data + // keeps changing, continue to defer the backup pass until things + // settle down, to avoid extra overhead. + mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL); + } + } + } + + // Schedule a backup pass for a given package, even if the caller is not part of + // that uid or package itself. + public void scheduleFullBackup(String packageName) throws RemoteException { + // !!! TODO: protect with a signature-or-system permission? + HashSet targets = new HashSet(); + synchronized (mQueueLock) { + int numKeys = mBackupParticipants.size(); + for (int index = 0; index < numKeys; index++) { + int uid = mBackupParticipants.keyAt(index); + HashSet servicesAtUid = mBackupParticipants.get(uid); + for (ServiceInfo service: servicesAtUid) { + if (service.packageName.equals(packageName)) { + mPendingBackups.put(new ComponentName(service.packageName, service.name), + new BackupRequest(service, true)); + } + } + } + } + } + + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (mQueueLock) { + int N = mBackupParticipants.size(); + pw.println("Participants:"); + for (int i=0; i services = mBackupParticipants.valueAt(i); + for (ServiceInfo s: services) { + pw.print(" "); + pw.println(s.toString()); + } + } + } + } +} diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index 73ff5016735ff18adb11c52ad73e84730f3d7fdb..90d8c9d4ca5d544ef6ed57ef6d8b7b814ae46cf2 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -84,7 +84,7 @@ class BatteryService extends Binder { private static final int CRITICAL_BATTERY_LEVEL = 4; private static final int DUMP_MAX_LENGTH = 24 * 1024; - private static final String[] DUMPSYS_ARGS = new String[] { "-c", "-u" }; + private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "-u" }; private static final String BATTERY_STATS_SERVICE_NAME = "batteryinfo"; private static final String DUMPSYS_DATA_PATH = "/data/system/"; @@ -229,6 +229,16 @@ class BatteryService extends Binder { EventLog.writeEvent(LOG_BATTERY_LEVEL, mBatteryLevel, mBatteryVoltage, mBatteryTemperature); } + if (mBatteryLevel != mLastBatteryLevel && mPlugType == BATTERY_PLUGGED_NONE) { + // If the battery level has changed and we are on battery, update the current level. + // This is used for discharge cycle tracking so this shouldn't be updated while the + // battery is charging. + try { + mBatteryStats.recordCurrentLevel(mBatteryLevel); + } catch (RemoteException e) { + // Should never happen. + } + } if (mBatteryLevelCritical && !mLastBatteryLevelCritical && mPlugType == BATTERY_PLUGGED_NONE) { // We want to make sure we log discharge cycle outliers @@ -237,6 +247,20 @@ class BatteryService extends Binder { logOutlier = true; } + // Separate broadcast is sent for power connected / not connected + // since the standard intent will not wake any applications and some + // applications may want to have smart behavior based on this. + if (mPlugType != 0 && mLastPlugType == 0) { + Intent intent = new Intent(Intent.ACTION_POWER_CONNECTED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + mContext.sendBroadcast(intent); + } + else if (mPlugType == 0 && mLastPlugType != 0) { + Intent intent = new Intent(Intent.ACTION_POWER_DISCONNECTED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + mContext.sendBroadcast(intent); + } + mLastBatteryStatus = mBatteryStatus; mLastBatteryHealth = mBatteryHealth; mLastBatteryPresent = mBatteryPresent; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 760988d9f382faca2f28e65f37ef3c6090ce3b28..493bd099065f0712c1a6b307ce3cba4ca5159c4c 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.provider.Sync; import android.util.EventLog; import android.util.Log; diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index 85861bbfe81a70d2e3efbcf3863a65e0549d78da..52e09ca260a552bdc434133b415dae55496bb71a 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -74,7 +74,7 @@ class DeviceStorageMonitorService extends Binder { private boolean mLowMemFlag=false; private Context mContext; private ContentResolver mContentResolver; - int mBlkSize; + long mBlkSize; long mTotalMemory; StatFs mFileStats; private static final String DATA_PATH="/data"; @@ -251,7 +251,7 @@ class DeviceStorageMonitorService extends Binder { //initialize block size mBlkSize = mFileStats.getBlockSize(); //initialize total storage on device - mTotalMemory = (mFileStats.getBlockCount()*mBlkSize)/100; + mTotalMemory = ((long)mFileStats.getBlockCount()*mBlkSize)/100L; mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW); mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK); checkMemory(true); diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java index c9066bedd96bdeb484555c112e650d7e7c8c24b1..3fc1e0ea58794f0853d5c97539276da7d1e350a3 100644 --- a/services/java/com/android/server/HeadsetObserver.java +++ b/services/java/com/android/server/HeadsetObserver.java @@ -21,6 +21,8 @@ import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.os.UEventObserver; import android.util.Log; import android.media.AudioManager; @@ -38,15 +40,19 @@ class HeadsetObserver extends UEventObserver { private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state"; private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name"; - private Context mContext; - private int mHeadsetState; private String mHeadsetName; private boolean mAudioRouteNeedsUpdate; private AudioManager mAudioManager; + private final Context mContext; + private final WakeLock mWakeLock; // held while there is a pending route change + public HeadsetObserver(Context context) { mContext = context; + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetObserver"); + mWakeLock.setReferenceCounted(false); startObserving(HEADSET_UEVENT_MATCH); @@ -103,6 +109,7 @@ class HeadsetObserver extends UEventObserver { // immediate, so delay the route change by 1000ms. // This could be improved once the audio sub-system provides an // interface to clear the audio pipeline. + mWakeLock.acquire(); mHandler.sendEmptyMessageDelayed(0, 1000); } else { updateAudioRoute(); @@ -138,7 +145,8 @@ class HeadsetObserver extends UEventObserver { @Override public void handleMessage(Message msg) { updateAudioRoute(); + mWakeLock.release(); } - }; + }; } diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java index b534ef10a974feaee0276e562109892465e2a1c5..72efca5eb4b9ee6f2ee79573883470dd9a025f92 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/java/com/android/server/IntentResolver.java @@ -16,6 +16,7 @@ package com.android.server; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -89,11 +90,11 @@ public class IntentResolver { } } - void dumpMap(Printer out, String prefix, Map> map) { + void dumpMap(PrintWriter out, String prefix, Map> map) { String eprefix = prefix + " "; String fprefix = prefix + " "; for (Map.Entry> e : map.entrySet()) { - out.println(eprefix + e.getKey() + ":"); + out.print(eprefix); out.print(e.getKey()); out.println(":"); ArrayList a = e.getValue(); final int N = a.size(); for (int i=0; i { } } - public void dump(Printer out, String prefix) { - out.println(prefix + "Full MIME Types:"); - dumpMap(out, prefix+" ", mTypeToFilter); - out.println(prefix); - out.println(prefix + "Base MIME Types:"); - dumpMap(out, prefix+" ", mBaseTypeToFilter); - out.println(prefix); - out.println(prefix + "Wild MIME Types:"); - dumpMap(out, prefix+" ", mWildTypeToFilter); - out.println(prefix); - out.println(prefix + "Schemes:"); - dumpMap(out, prefix+" ", mSchemeToFilter); - out.println(prefix); - out.println(prefix + "Non-Data Actions:"); - dumpMap(out, prefix+" ", mActionToFilter); - out.println(prefix); - out.println(prefix + "MIME Typed Actions:"); - dumpMap(out, prefix+" ", mTypedActionToFilter); + public void dump(PrintWriter out, String prefix) { + String innerPrefix = prefix + " "; + out.print(prefix); out.println("Full MIME Types:"); + dumpMap(out, innerPrefix, mTypeToFilter); + out.println(" "); + out.print(prefix); out.println("Base MIME Types:"); + dumpMap(out, innerPrefix, mBaseTypeToFilter); + out.println(" "); + out.print(prefix); out.println("Wild MIME Types:"); + dumpMap(out, innerPrefix, mWildTypeToFilter); + out.println(" "); + out.print(prefix); out.println("Schemes:"); + dumpMap(out, innerPrefix, mSchemeToFilter); + out.println(" "); + out.print(prefix); out.println("Non-Data Actions:"); + dumpMap(out, innerPrefix, mActionToFilter); + out.println(" "); + out.print(prefix); out.println("MIME Typed Actions:"); + dumpMap(out, innerPrefix, mTypedActionToFilter); } private class IteratorWrapper implements Iterator { @@ -275,8 +277,8 @@ public class IntentResolver { Collections.sort(results, mResolvePrioritySorter); } - protected void dumpFilter(Printer out, String prefix, F filter) { - out.println(prefix + filter); + protected void dumpFilter(PrintWriter out, String prefix, F filter) { + out.print(prefix); out.println(filter); } private final int register_mime_types(F filter, String prefix) { diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 705ddb3b7acd2a40dadc47fc38457e7a37aeb840..05888e03d4eaaf69b3dfcb2985b7335dad1415d1 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -28,53 +28,52 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Observable; +import java.util.Observer; import java.util.Set; import java.util.regex.Pattern; -import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.database.Cursor; import android.location.Address; +import android.location.IGeocodeProvider; import android.location.IGpsStatusListener; +import android.location.IGpsStatusProvider; +import android.location.ILocationCollector; import android.location.ILocationListener; import android.location.ILocationManager; +import android.location.ILocationProvider; import android.location.Location; import android.location.LocationManager; import android.location.LocationProvider; -import android.location.LocationProviderImpl; import android.net.ConnectivityManager; import android.net.Uri; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; -import android.telephony.CellLocation; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; import android.util.Config; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.SparseIntArray; -import com.android.internal.app.IBatteryStats; -import com.android.internal.location.CellState; import com.android.internal.location.GpsLocationProvider; -import com.android.internal.location.ILocationCollector; -import com.android.internal.location.INetworkLocationManager; -import com.android.internal.location.INetworkLocationProvider; -import com.android.internal.location.TrackProvider; +import com.android.internal.location.LocationProviderProxy; +import com.android.internal.location.MockProvider; import com.android.server.am.BatteryStatsService; /** @@ -83,8 +82,7 @@ import com.android.server.am.BatteryStatsService; * * {@hide} */ -public class LocationManagerService extends ILocationManager.Stub - implements INetworkLocationManager { +public class LocationManagerService extends ILocationManager.Stub implements Runnable { private static final String TAG = "LocationManagerService"; private static final boolean LOCAL_LOGV = false; @@ -94,10 +92,6 @@ public class LocationManagerService extends ILocationManager.Stub // Max time to hold wake lock for, in milliseconds. private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L; - // Time to wait after releasing a wake lock for clients to process location update, - // in milliseconds. - private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L; - // The last time a location was written, by provider name. private HashMap mLastWriteTime = new HashMap(); @@ -111,6 +105,10 @@ public class LocationManagerService extends ILocationManager.Stub android.Manifest.permission.ACCESS_MOCK_LOCATION; private static final String ACCESS_LOCATION_EXTRA_COMMANDS = android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; + private static final String INSTALL_LOCATION_PROVIDER = + android.Manifest.permission.INSTALL_LOCATION_PROVIDER; + private static final String INSTALL_LOCATION_COLLECTOR = + android.Manifest.permission.INSTALL_LOCATION_COLLECTOR; // Set of providers that are explicitly enabled private final Set mEnabledProviders = new HashSet(); @@ -119,70 +117,41 @@ public class LocationManagerService extends ILocationManager.Stub private final Set mDisabledProviders = new HashSet(); // Locations, status values, and extras for mock providers - HashMap mMockProviders = new HashMap(); - private final HashMap mMockProviderLocation = new HashMap(); - private final HashMap mMockProviderStatus = new HashMap(); - private final HashMap mMockProviderStatusExtras = new HashMap(); - private final HashMap mMockProviderStatusUpdateTime = new HashMap(); + private final HashMap mMockProviders = new HashMap(); private static boolean sProvidersLoaded = false; private final Context mContext; - private GpsLocationProvider mGpsLocationProvider; - private boolean mGpsNavigating; - private LocationProviderImpl mNetworkLocationProvider; - private INetworkLocationProvider mNetworkLocationInterface; + private IGeocodeProvider mGeocodeProvider; + private IGpsStatusProvider mGpsStatusProvider; private LocationWorkerHandler mLocationHandler; // Handler messages - private static final int MESSAGE_HEARTBEAT = 1; - private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2; - private static final int MESSAGE_RELEASE_WAKE_LOCK = 3; - private static final int MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER = 4; + private static final int MESSAGE_LOCATION_CHANGED = 1; - // Alarm manager and wakelock variables - private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT"; + // wakelock variables private final static String WAKELOCK_KEY = "LocationManagerService"; - private final static String WIFILOCK_KEY = "LocationManagerService"; - private AlarmManager mAlarmManager; - private long mAlarmInterval = 0; - private boolean mScreenOn = true; private PowerManager.WakeLock mWakeLock = null; - private WifiManager.WifiLock mWifiLock = null; - private long mWakeLockAcquireTime = 0; - private boolean mWakeLockGpsReceived = true; - private boolean mWakeLockNetworkReceived = true; - private boolean mWifiWakeLockAcquired = false; - private boolean mCellWakeLockAcquired = false; - - private final IBatteryStats mBatteryStats; + private int mPendingBroadcasts; /** - * Mapping from listener IBinder/PendingIntent to local Listener wrappers. + * List of all receivers. */ - private final ArrayList mListeners = new ArrayList(); + private final HashMap mReceivers = new HashMap(); + /** - * Used for reporting which UIDs are causing the GPS to run. - */ - private final SparseIntArray mReportedGpsUids = new SparseIntArray(); - private int mReportedGpsSeq = 0; - - /** - * Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord. - * This also serves as the lock for our state. + * List of location providers. */ - private final HashMap> mLocationListeners = - new HashMap>(); + private final ArrayList mProviders = + new ArrayList(); + private final HashMap mProvidersByName + = new HashMap(); /** - * Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast - * location. + * Object used internally for synchronization */ - private final HashMap> mLastFixBroadcast = - new HashMap>(); - private final HashMap> mLastStatusBroadcast = - new HashMap>(); + private final Object mLock = new Object(); /** * Mapping from provider name to all its UpdateRecords @@ -190,15 +159,9 @@ public class LocationManagerService extends ILocationManager.Stub private final HashMap> mRecordsByProvider = new HashMap>(); - /** - * Mappings from provider name to object to use for current location. Locations - * contained in this list may not always be valid. - */ - private final HashMap mLocationsByProvider = - new HashMap(); - // Proximity listeners - private Receiver mProximityListener = null; + private Receiver mProximityReceiver = null; + private ILocationListener mProximityListener = null; private HashMap mProximityAlerts = new HashMap(); private HashSet mProximitiesEntered = @@ -208,44 +171,34 @@ public class LocationManagerService extends ILocationManager.Stub private HashMap mLastKnownLocation = new HashMap(); - // Battery status extras (from com.android.server.BatteryService) - private static final String BATTERY_EXTRA_SCALE = "scale"; - private static final String BATTERY_EXTRA_LEVEL = "level"; - private static final String BATTERY_EXTRA_PLUGGED = "plugged"; - - // Last known cell service state - private TelephonyManager mTelephonyManager; - // Location collector private ILocationCollector mCollector; - // Wifi Manager - private WifiManager mWifiManager; - private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; - private boolean mWifiEnabled = false; + + // for Settings change notification + private ContentQueryMap mSettings; /** * A wrapper class holding either an ILocationListener or a PendingIntent to receive * location updates. */ - private final class Receiver implements IBinder.DeathRecipient { + private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { final ILocationListener mListener; final PendingIntent mPendingIntent; - final int mUid; final Object mKey; + final HashMap mUpdateRecords = new HashMap(); + int mPendingBroadcasts; - Receiver(ILocationListener listener, int uid) { + Receiver(ILocationListener listener) { mListener = listener; mPendingIntent = null; - mUid = uid; mKey = listener.asBinder(); } - Receiver(PendingIntent intent, int uid) { + Receiver(PendingIntent intent) { mPendingIntent = intent; mListener = null; - mUid = uid; mKey = intent; } @@ -262,18 +215,17 @@ public class LocationManagerService extends ILocationManager.Stub public int hashCode() { return mKey.hashCode(); } - - + @Override public String toString() { if (mListener != null) { return "Receiver{" + Integer.toHexString(System.identityHashCode(this)) - + " uid " + mUid + " Listener " + mKey + "}"; + + " Listener " + mKey + "}"; } else { return "Receiver{" + Integer.toHexString(System.identityHashCode(this)) - + " uid " + mUid + " Intent " + mKey + "}"; + + " Intent " + mKey + "}"; } } @@ -302,7 +254,16 @@ public class LocationManagerService extends ILocationManager.Stub public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { if (mListener != null) { try { - mListener.onStatusChanged(provider, status, extras); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mListener.onStatusChanged(provider, status, extras); + if (mListener != mProximityListener) { + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } } catch (RemoteException e) { return false; } @@ -311,7 +272,14 @@ public class LocationManagerService extends ILocationManager.Stub statusChanged.putExtras(extras); statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); try { - mPendingIntent.send(mContext, 0, statusChanged, null, null); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } } catch (PendingIntent.CanceledException e) { return false; } @@ -322,7 +290,16 @@ public class LocationManagerService extends ILocationManager.Stub public boolean callLocationChangedLocked(Location location) { if (mListener != null) { try { - mListener.onLocationChanged(location); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mListener.onLocationChanged(location); + if (mListener != mProximityListener) { + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } } catch (RemoteException e) { return false; } @@ -330,7 +307,53 @@ public class LocationManagerService extends ILocationManager.Stub Intent locationChanged = new Intent(); locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); try { - mPendingIntent.send(mContext, 0, locationChanged, null, null); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } catch (PendingIntent.CanceledException e) { + return false; + } + } + return true; + } + + public boolean callProviderEnabledLocked(String provider, boolean enabled) { + if (mListener != null) { + try { + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + if (enabled) { + mListener.onProviderEnabled(provider); + } else { + mListener.onProviderDisabled(provider); + } + if (mListener != mProximityListener) { + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } + } catch (RemoteException e) { + return false; + } + } else { + Intent providerIntent = new Intent(); + providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); + try { + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } } catch (PendingIntent.CanceledException e) { return false; } @@ -342,9 +365,56 @@ public class LocationManagerService extends ILocationManager.Stub if (LOCAL_LOGV) { Log.v(TAG, "Location listener died"); } - synchronized (mLocationListeners) { + synchronized (mLock) { removeUpdatesLocked(this); } + synchronized (this) { + if (mPendingBroadcasts > 0) { + LocationManagerService.this.decrementPendingBroadcasts(); + mPendingBroadcasts = 0; + } + } + } + + public void onSendFinished(PendingIntent pendingIntent, Intent intent, + int resultCode, String resultData, Bundle resultExtras) { + synchronized (this) { + decrementPendingBroadcastsLocked(); + } + } + + // this must be called while synchronized by caller in a synchronized block + // containing the sending of the broadcaset + private void incrementPendingBroadcastsLocked() { + if (mPendingBroadcasts++ == 0) { + LocationManagerService.this.incrementPendingBroadcasts(); + } + } + + private void decrementPendingBroadcastsLocked() { + if (--mPendingBroadcasts == 0) { + LocationManagerService.this.decrementPendingBroadcasts(); + } + } + } + + public void locationCallbackFinished(ILocationListener listener) { + Receiver receiver = getReceiver(listener); + if (receiver != null) { + synchronized (receiver) { + // so wakelock calls will succeed + long identity = Binder.clearCallingIdentity(); + receiver.decrementPendingBroadcastsLocked(); + Binder.restoreCallingIdentity(identity); + } + } + } + + private final class SettingsObserver implements Observer { + public void update(Observable o, Object arg) { + synchronized (mLock) { + updateProvidersLocked(); + } } } @@ -439,17 +509,18 @@ public class LocationManagerService extends ILocationManager.Stub } } - /** - * Load providers from /data/location// - * class - * kml - * nmea - * track - * location - * properties - */ + private void addProvider(LocationProviderProxy provider) { + mProviders.add(provider); + mProvidersByName.put(provider.getName(), provider); + } + + private void removeProvider(LocationProviderProxy provider) { + mProviders.remove(provider); + mProvidersByName.remove(provider.getName()); + } + private void loadProviders() { - synchronized (mLocationListeners) { + synchronized (mLock) { if (sProvidersLoaded) { return; } @@ -472,73 +543,10 @@ public class LocationManagerService extends ILocationManager.Stub // Attempt to load "real" providers first if (GpsLocationProvider.isSupported()) { // Create a gps location provider - mGpsLocationProvider = new GpsLocationProvider(mContext); - LocationProviderImpl.addProvider(mGpsLocationProvider); - } - - // Load fake providers if real providers are not available - File f = new File(LocationManager.PROVIDER_DIR); - if (f.isDirectory()) { - File[] subdirs = f.listFiles(); - for (int i = 0; i < subdirs.length; i++) { - if (!subdirs[i].isDirectory()) { - continue; - } - - String name = subdirs[i].getName(); - - if (LOCAL_LOGV) { - Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath()); - Log.v(TAG, "name = " + name); - } - - // Don't create a fake provider if a real provider exists - if (LocationProviderImpl.getProvider(name) == null) { - LocationProviderImpl provider = null; - try { - File classFile = new File(subdirs[i], "class"); - // Look for a 'class' file - provider = LocationProviderImpl.loadFromClass(classFile); - - // Look for an 'kml', 'nmea', or 'track' file - if (provider == null) { - // Load properties from 'properties' file, if present - File propertiesFile = new File(subdirs[i], "properties"); - - if (propertiesFile.exists()) { - provider = new TrackProvider(name); - ((TrackProvider)provider).readProperties(propertiesFile); - - File kmlFile = new File(subdirs[i], "kml"); - if (kmlFile.exists()) { - ((TrackProvider) provider).readKml(kmlFile); - } else { - File nmeaFile = new File(subdirs[i], "nmea"); - if (nmeaFile.exists()) { - ((TrackProvider) provider).readNmea(name, nmeaFile); - } else { - File trackFile = new File(subdirs[i], "track"); - if (trackFile.exists()) { - ((TrackProvider) provider).readTrack(trackFile); - } - } - } - } - } - if (provider != null) { - LocationProviderImpl.addProvider(provider); - } - // Grab the initial location of a TrackProvider and - // store it as the last known location for that provider - if (provider instanceof TrackProvider) { - TrackProvider tp = (TrackProvider) provider; - mLastKnownLocation.put(tp.getName(), tp.getInitialLocation()); - } - } catch (Exception e) { - Log.e(TAG, "Exception loading provder " + name, e); - } - } - } + GpsLocationProvider provider = new GpsLocationProvider(mContext, this); + mGpsStatusProvider = provider.getGpsStatusProvider(); + LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider); + addProvider(proxy); } updateProvidersLocked(); @@ -550,118 +558,95 @@ public class LocationManagerService extends ILocationManager.Stub public LocationManagerService(Context context) { super(); mContext = context; - mLocationHandler = new LocationWorkerHandler(); + + Thread thread = new Thread(null, this, "LocationManagerService"); + thread.start(); if (LOCAL_LOGV) { Log.v(TAG, "Constructed LocationManager Service"); } + } - // Alarm manager, needs to be done before calling loadProviders() below - mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - + private void initialize() { // 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); - - // Battery statistics service to be notified when GPS turns on or off - mBatteryStats = BatteryStatsService.getService(); // Load providers loadProviders(); - // Listen for Radio changes - mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); - mTelephonyManager.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_CELL_LOCATION | - PhoneStateListener.LISTEN_SIGNAL_STRENGTH | - PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); - // Register for Network (Wifi or Mobile) updates - NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver(); - IntentFilter networkIntentFilter = new IntentFilter(); - networkIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - networkIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); - context.registerReceiver(networkReceiver, networkIntentFilter); - - // Register for power updates - PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ALARM_INTENT); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - intentFilter.addAction(Intent.ACTION_SCREEN_ON); - intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); + intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + // Register for Package Manager updates intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); - context.registerReceiver(powerStateReceiver, intentFilter); - - // Get the wifi manager - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + mContext.registerReceiver(mBroadcastReceiver, intentFilter); - // Create a wifi lock for future use - mWifiLock = getWifiWakelockLocked(); + // listen for settings changes + ContentResolver resolver = mContext.getContentResolver(); + Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, + "(" + Settings.System.NAME + "=?)", + new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, + null); + mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler); + SettingsObserver settingsObserver = new SettingsObserver(); + mSettings.addObserver(settingsObserver); + } + + public void run() + { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + Looper.prepare(); + mLocationHandler = new LocationWorkerHandler(); + initialize(); + Looper.loop(); } - public void setInstallCallback(InstallCallback callback) { - synchronized (mLocationListeners) { - mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER); - Message m = Message.obtain(mLocationHandler, - MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback); - mLocationHandler.sendMessageAtFrontOfQueue(m); + public void installLocationProvider(String name, ILocationProvider provider) { + if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); } - } - - public void setNetworkLocationProvider(INetworkLocationProvider provider) { - synchronized (mLocationListeners) { - mNetworkLocationInterface = provider; - provider.addListener(getPackageNames()); - mNetworkLocationProvider = (LocationProviderImpl)provider; - LocationProviderImpl.addProvider(mNetworkLocationProvider); - updateProvidersLocked(); - - // notify NetworkLocationProvider of any events it might have missed - synchronized (mLocationListeners) { - mNetworkLocationProvider.updateNetworkState(mNetworkState); - mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled); - mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); - - if (mLastCellState != null) { - if (mCollector != null) { - mCollector.updateCellState(mLastCellState); - } - mNetworkLocationProvider.updateCellState(mLastCellState); - } - // There might be an existing wifi scan available - if (mWifiManager != null) { - List wifiScanResults = mWifiManager.getScanResults(); - if (wifiScanResults != null && wifiScanResults.size() != 0) { - mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); - if (mCollector != null) { - mCollector.updateWifiScanResults(wifiScanResults); - } - } + synchronized (mLock) { + // check to see if we are reinstalling a dead provider + LocationProviderProxy oldProvider = mProvidersByName.get(name); + if (oldProvider != null) { + if (oldProvider.isDead()) { + Log.d(TAG, "replacing dead provider"); + removeProvider(oldProvider); + } else { + throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); } } + + LocationProviderProxy proxy = new LocationProviderProxy(name, provider); + addProvider(proxy); + updateProvidersLocked(); + + // notify provider of current network state + proxy.updateNetworkState(mNetworkState); } } - public void setLocationCollector(ILocationCollector collector) { - synchronized (mLocationListeners) { - mCollector = collector; - if (mGpsLocationProvider != null) { - mGpsLocationProvider.setLocationCollector(mCollector); - } + public void installLocationCollector(ILocationCollector collector) { + if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_COLLECTOR) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires INSTALL_LOCATION_COLLECTOR permission"); } + + // FIXME - only support one collector + mCollector = collector; } - private WifiManager.WifiLock getWifiWakelockLocked() { - if (mWifiLock == null && mWifiManager != null) { - mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY); - mWifiLock.setReferenceCounted(false); + public void installGeocodeProvider(IGeocodeProvider provider) { + if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); } - return mWifiLock; + + mGeocodeProvider = provider; } private boolean isAllowedBySettingsLocked(String provider) { @@ -712,15 +697,9 @@ public class LocationManagerService extends ILocationManager.Stub return true; } - private String[] getPackageNames() { - // Since a single UID may correspond to multiple packages, this can only be used as an - // approximation for tracking - return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid()); - } - public List getAllProviders() { try { - synchronized (mLocationListeners) { + synchronized (mLock) { return _getAllProvidersLocked(); } } catch (SecurityException se) { @@ -735,10 +714,9 @@ public class LocationManagerService extends ILocationManager.Stub if (LOCAL_LOGV) { Log.v(TAG, "getAllProviders"); } - List providers = LocationProviderImpl.getProviders(); - ArrayList out = new ArrayList(providers.size()); - - for (LocationProviderImpl p : providers) { + ArrayList out = new ArrayList(mProviders.size()); + for (int i = mProviders.size() - 1; i >= 0; i--) { + LocationProviderProxy p = mProviders.get(i); out.add(p.getName()); } return out; @@ -746,7 +724,7 @@ public class LocationManagerService extends ILocationManager.Stub public List getProviders(boolean enabledOnly) { try { - synchronized (mLocationListeners) { + synchronized (mLock) { return _getProvidersLocked(enabledOnly); } } catch (SecurityException se) { @@ -761,10 +739,9 @@ public class LocationManagerService extends ILocationManager.Stub if (LOCAL_LOGV) { Log.v(TAG, "getProviders"); } - List providers = LocationProviderImpl.getProviders(); - ArrayList out = new ArrayList(); - - for (LocationProviderImpl p : providers) { + ArrayList out = new ArrayList(mProviders.size()); + for (int i = mProviders.size() - 1; i >= 0; i--) { + LocationProviderProxy p = mProviders.get(i); String name = p.getName(); if (isAllowedProviderSafe(name)) { if (enabledOnly && !isAllowedBySettingsLocked(name)) { @@ -776,24 +753,13 @@ public class LocationManagerService extends ILocationManager.Stub return out; } - public void updateProviders() { - synchronized (mLocationListeners) { - updateProvidersLocked(); - } - } - private void updateProvidersLocked() { - for (LocationProviderImpl p : LocationProviderImpl.getProviders()) { + for (int i = mProviders.size() - 1; i >= 0; i--) { + LocationProviderProxy p = mProviders.get(i); boolean isEnabled = p.isEnabled(); String name = p.getName(); boolean shouldBeEnabled = isAllowedBySettingsLocked(name); - // Collection is only allowed when network provider is being used - if (mCollector != null && - p.getName().equals(LocationManager.NETWORK_PROVIDER)) { - mCollector.updateNetworkProviderStatus(shouldBeEnabled); - } - if (isEnabled && !shouldBeEnabled) { updateProviderListenersLocked(name, false); } else if (!isEnabled && shouldBeEnabled) { @@ -806,7 +772,7 @@ public class LocationManagerService extends ILocationManager.Stub private void updateProviderListenersLocked(String provider, boolean enabled) { int listeners = 0; - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); + LocationProviderProxy p = mProvidersByName.get(provider); if (p == null) { return; } @@ -819,29 +785,11 @@ public class LocationManagerService extends ILocationManager.Stub for (int i=0; i(); - deadReceivers.add(receiver); - } - } + if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { + if (deadReceivers == null) { + deadReceivers = new ArrayList(); + deadReceivers.add(record.mReceiver); } - } catch (RemoteException e) { - // The death link will clean this up. } listeners++; } @@ -858,24 +806,10 @@ public class LocationManagerService extends ILocationManager.Stub if (listeners > 0) { p.setMinTime(getMinTimeLocked(provider)); p.enableLocationTracking(true); - updateWakelockStatusLocked(mScreenOn); } } else { p.enableLocationTracking(false); - if (p == mGpsLocationProvider) { - mGpsNavigating = false; - reportStopGpsLocked(); - } p.disable(); - updateWakelockStatusLocked(mScreenOn); - } - - if (enabled && listeners > 0) { - mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); - Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); - mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); - } else { - mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); } } @@ -896,19 +830,19 @@ public class LocationManagerService extends ILocationManager.Stub final long mMinTime; final float mMinDistance; final int mUid; - final String[] mPackages; + Location mLastFixBroadcast; + long mLastStatusBroadcast; /** * Note: must be constructed with lock held. */ UpdateRecord(String provider, long minTime, float minDistance, - Receiver receiver, int uid, String[] packages) { + Receiver receiver, int uid) { mProvider = provider; mReceiver = receiver; mMinTime = minTime; mMinDistance = minDistance; mUid = uid; - mPackages = packages; ArrayList records = mRecordsByProvider.get(provider); if (records == null) { @@ -940,33 +874,74 @@ public class LocationManagerService extends ILocationManager.Stub pw.println(prefix + this); pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver); pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance); - StringBuilder sb = new StringBuilder(); - if (mPackages != null) { - for (int i=0; i 0) sb.append(", "); - sb.append(mPackages[i]); - } - } - pw.println(prefix + "mUid=" + mUid + " mPackages=" + sb); + pw.println(prefix + "mUid=" + mUid); + pw.println(prefix + "mLastFixBroadcast:"); + mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " "); + pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast); } /** * Calls dispose(). */ @Override protected void finalize() { - synchronized (mLocationListeners) { + synchronized (mLock) { disposeLocked(); } } } + private Receiver getReceiver(ILocationListener listener) { + IBinder binder = listener.asBinder(); + Receiver receiver = mReceivers.get(binder); + if (receiver == null) { + receiver = new Receiver(listener); + mReceivers.put(binder, receiver); + + try { + if (receiver.isListener()) { + receiver.getListener().asBinder().linkToDeath(receiver, 0); + } + } catch (RemoteException e) { + Log.e(TAG, "linkToDeath failed:", e); + return null; + } + } + return receiver; + } + + private Receiver getReceiver(PendingIntent intent) { + Receiver receiver = mReceivers.get(intent); + if (receiver == null) { + receiver = new Receiver(intent); + mReceivers.put(intent, receiver); + } + return receiver; + } + + private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) { + ArrayList records = mRecordsByProvider.get(provider); + if (records != null) { + for (int i = records.size() - 1; i >= 0; i--) { + UpdateRecord record = records.get(i); + if (record.mUid == uid && record.mReceiver != excludedReceiver) { + return true; + } + } + } + for (ProximityAlert alert : mProximityAlerts.values()) { + if (alert.mUid == uid) { + return true; + } + } + return false; + } + public void requestLocationUpdates(String provider, long minTime, float minDistance, ILocationListener listener) { try { - synchronized (mLocationListeners) { - requestLocationUpdatesLocked(provider, minTime, minDistance, - new Receiver(listener, Binder.getCallingUid())); + synchronized (mLock) { + requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener)); } } catch (SecurityException se) { throw se; @@ -978,9 +953,8 @@ public class LocationManagerService extends ILocationManager.Stub public void requestLocationUpdatesPI(String provider, long minTime, float minDistance, PendingIntent intent) { try { - synchronized (mLocationListeners) { - requestLocationUpdatesLocked(provider, minTime, minDistance, - new Receiver(intent, Binder.getCallingUid())); + synchronized (mLock) { + requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent)); } } catch (SecurityException se) { throw se; @@ -995,69 +969,36 @@ public class LocationManagerService extends ILocationManager.Stub Log.v(TAG, "_requestLocationUpdates: listener = " + receiver); } - LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); - if (impl == null) { + LocationProviderProxy proxy = mProvidersByName.get(provider); + if (proxy == null) { throw new IllegalArgumentException("provider=" + provider); } checkPermissionsSafe(provider); - String[] packages = getPackageNames(); - // so wakelock calls will succeed final int callingUid = Binder.getCallingUid(); + boolean newUid = !providerHasListener(provider, callingUid, null); long identity = Binder.clearCallingIdentity(); try { - UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, - receiver, callingUid, packages); - if (!mListeners.contains(receiver)) { - try { - if (receiver.isListener()) { - receiver.getListener().asBinder().linkToDeath(receiver, 0); - } - mListeners.add(receiver); - } catch (RemoteException e) { - return; - } - } - - HashMap records = mLocationListeners.get(receiver); - if (records == null) { - records = new HashMap(); - mLocationListeners.put(receiver, records); - } - UpdateRecord oldRecord = records.put(provider, r); + UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid); + UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r); if (oldRecord != null) { oldRecord.disposeLocked(); } + if (newUid) { + proxy.addListener(callingUid); + } + boolean isProviderEnabled = isAllowedBySettingsLocked(provider); if (isProviderEnabled) { long minTimeForProvider = getMinTimeLocked(provider); - impl.setMinTime(minTimeForProvider); - impl.enableLocationTracking(true); - updateWakelockStatusLocked(mScreenOn); - - if (provider.equals(LocationManager.GPS_PROVIDER)) { - if (mGpsNavigating) { - updateReportedGpsLocked(); - } - } - - // Clear heartbeats if any before starting a new one - mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); - Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); - mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); + proxy.setMinTime(minTimeForProvider); + proxy.enableLocationTracking(true); } else { - try { - // Notify the listener that updates are currently disabled - if (receiver.isListener()) { - receiver.getListener().onProviderDisabled(provider); - } - } catch(RemoteException e) { - Log.w(TAG, "RemoteException calling onProviderDisabled on " + - receiver.getListener()); - } + // Notify the listener that updates are currently disabled + receiver.callProviderEnabledLocked(provider, false); } } finally { Binder.restoreCallingIdentity(identity); @@ -1066,8 +1007,8 @@ public class LocationManagerService extends ILocationManager.Stub public void removeUpdates(ILocationListener listener) { try { - synchronized (mLocationListeners) { - removeUpdatesLocked(new Receiver(listener, Binder.getCallingUid())); + synchronized (mLock) { + removeUpdatesLocked(getReceiver(listener)); } } catch (SecurityException se) { throw se; @@ -1078,8 +1019,8 @@ public class LocationManagerService extends ILocationManager.Stub public void removeUpdatesPI(PendingIntent intent) { try { - synchronized (mLocationListeners) { - removeUpdatesLocked(new Receiver(intent, Binder.getCallingUid())); + synchronized (mLock) { + removeUpdatesLocked(getReceiver(intent)); } } catch (SecurityException se) { throw se; @@ -1097,23 +1038,20 @@ public class LocationManagerService extends ILocationManager.Stub final int callingUid = Binder.getCallingUid(); long identity = Binder.clearCallingIdentity(); try { - int idx = mListeners.indexOf(receiver); - if (idx >= 0) { - Receiver myReceiver = mListeners.remove(idx); - if (myReceiver.isListener()) { - myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0); - } + if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { + receiver.getListener().asBinder().unlinkToDeath(receiver, 0); } // Record which providers were associated with this listener HashSet providers = new HashSet(); - HashMap oldRecords = mLocationListeners.get(receiver); + HashMap oldRecords = receiver.mUpdateRecords; if (oldRecords != null) { // Call dispose() on the obsolete update records. for (UpdateRecord record : oldRecords.values()) { - if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) { - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.removeListener(record.mPackages); + if (!providerHasListener(record.mProvider, callingUid, receiver)) { + LocationProviderProxy proxy = mProvidersByName.get(record.mProvider); + if (proxy != null) { + proxy.removeListener(callingUid); } } record.disposeLocked(); @@ -1121,10 +1059,6 @@ public class LocationManagerService extends ILocationManager.Stub // Accumulate providers providers.addAll(oldRecords.keySet()); } - - mLocationListeners.remove(receiver); - mLastFixBroadcast.remove(receiver); - mLastStatusBroadcast.remove(receiver); // See if the providers associated with this listener have any // other listeners; if one does, inform it of the new smallest minTime @@ -1141,29 +1075,22 @@ public class LocationManagerService extends ILocationManager.Stub hasOtherListener = true; } - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); + LocationProviderProxy p = mProvidersByName.get(provider); if (p != null) { if (hasOtherListener) { p.setMinTime(getMinTimeLocked(provider)); } else { - mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); p.enableLocationTracking(false); } - - if (p == mGpsLocationProvider && mGpsNavigating) { - updateReportedGpsLocked(); - } } } - - updateWakelockStatusLocked(mScreenOn); } finally { Binder.restoreCallingIdentity(identity); } } public boolean addGpsStatusListener(IGpsStatusListener listener) { - if (mGpsLocationProvider == null) { + if (mGpsStatusProvider == null) { return false; } if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) != @@ -1172,17 +1099,21 @@ public class LocationManagerService extends ILocationManager.Stub } try { - mGpsLocationProvider.addGpsStatusListener(listener); + mGpsStatusProvider.addGpsStatusListener(listener); } catch (RemoteException e) { - Log.w(TAG, "RemoteException in addGpsStatusListener"); + Log.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); return false; } return true; } public void removeGpsStatusListener(IGpsStatusListener listener) { - synchronized (mLocationListeners) { - mGpsLocationProvider.removeGpsStatusListener(listener); + synchronized (mLock) { + try { + mGpsStatusProvider.removeGpsStatusListener(listener); + } catch (Exception e) { + Log.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); + } } } @@ -1195,13 +1126,13 @@ public class LocationManagerService extends ILocationManager.Stub throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); } - synchronized (mLocationListeners) { - LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); + synchronized (mLock) { + LocationProviderProxy proxy = mProvidersByName.get(provider); if (provider == null) { return false; } - return impl.sendExtraCommand(command, extras); + return proxy.sendExtraCommand(command, extras); } } @@ -1263,7 +1194,7 @@ public class LocationManagerService extends ILocationManager.Stub } // Listener for receiving locations to trigger proximity alerts - class ProximityListener extends ILocationListener.Stub { + class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished { boolean isGpsAvailable = false; @@ -1300,7 +1231,14 @@ public class LocationManagerService extends ILocationManager.Stub Intent enteredIntent = new Intent(); enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); try { - intent.send(mContext, 0, enteredIntent, null, null); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcasts() + // is called before decrementPendingBroadcasts() + intent.send(mContext, 0, enteredIntent, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcasts(); + } } catch (PendingIntent.CanceledException e) { if (LOCAL_LOGV) { Log.v(TAG, "Canceled proximity alert: " + alert, e); @@ -1318,7 +1256,14 @@ public class LocationManagerService extends ILocationManager.Stub Intent exitedIntent = new Intent(); exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); try { - intent.send(mContext, 0, exitedIntent, null, null); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcasts() + // is called before decrementPendingBroadcasts() + intent.send(mContext, 0, exitedIntent, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcasts(); + } } catch (PendingIntent.CanceledException e) { if (LOCAL_LOGV) { Log.v(TAG, "Canceled proximity alert: " + alert, e); @@ -1371,12 +1316,21 @@ public class LocationManagerService extends ILocationManager.Stub isGpsAvailable = false; } } + + public void onSendFinished(PendingIntent pendingIntent, Intent intent, + int resultCode, String resultData, Bundle resultExtras) { + // synchronize to ensure incrementPendingBroadcasts() + // is called before decrementPendingBroadcasts() + synchronized (this) { + decrementPendingBroadcasts(); + } + } } public void addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent) { try { - synchronized (mLocationListeners) { + synchronized (mLock) { addProximityAlertLocked(latitude, longitude, radius, expiration, intent); } } catch (SecurityException se) { @@ -1408,28 +1362,20 @@ public class LocationManagerService extends ILocationManager.Stub latitude, longitude, radius, expiration, intent); mProximityAlerts.put(intent, alert); - if (mProximityListener == null) { - mProximityListener = new Receiver(new ProximityListener(), -1); - - LocationProvider provider = LocationProviderImpl.getProvider( - LocationManager.GPS_PROVIDER); - if (provider != null) { - requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); - } + if (mProximityReceiver == null) { + mProximityListener = new ProximityListener(); + mProximityReceiver = new Receiver(mProximityListener); - provider = - LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER); - if (provider != null) { - requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); + for (int i = mProviders.size() - 1; i >= 0; i--) { + LocationProviderProxy provider = mProviders.get(i); + requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver); } - } else if (mGpsNavigating) { - updateReportedGpsLocked(); } } public void removeProximityAlert(PendingIntent intent) { try { - synchronized (mLocationListeners) { + synchronized (mLock) { removeProximityAlertLocked(intent); } } catch (SecurityException se) { @@ -1446,10 +1392,9 @@ public class LocationManagerService extends ILocationManager.Stub mProximityAlerts.remove(intent); if (mProximityAlerts.size() == 0) { - removeUpdatesLocked(mProximityListener); + removeUpdatesLocked(mProximityReceiver); + mProximityReceiver = null; mProximityListener = null; - } else if (mGpsNavigating) { - updateReportedGpsLocked(); } } @@ -1460,7 +1405,7 @@ public class LocationManagerService extends ILocationManager.Stub */ public Bundle getProviderInfo(String provider) { try { - synchronized (mLocationListeners) { + synchronized (mLock) { return _getProviderInfoLocked(provider); } } catch (SecurityException se) { @@ -1472,7 +1417,7 @@ public class LocationManagerService extends ILocationManager.Stub } private Bundle _getProviderInfoLocked(String provider) { - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); + LocationProviderProxy p = mProvidersByName.get(provider); if (p == null) { return null; } @@ -1495,7 +1440,7 @@ public class LocationManagerService extends ILocationManager.Stub public boolean isProviderEnabled(String provider) { try { - synchronized (mLocationListeners) { + synchronized (mLock) { return _isProviderEnabledLocked(provider); } } catch (SecurityException se) { @@ -1506,10 +1451,21 @@ public class LocationManagerService extends ILocationManager.Stub } } + public void reportLocation(Location location) { + if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); + } + + mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location); + Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location); + mLocationHandler.sendMessageAtFrontOfQueue(m); + } + private boolean _isProviderEnabledLocked(String provider) { checkPermissionsSafe(provider); - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); + LocationProviderProxy p = mProvidersByName.get(provider); if (p == null) { throw new IllegalArgumentException("provider=" + provider); } @@ -1518,7 +1474,7 @@ public class LocationManagerService extends ILocationManager.Stub public Location getLastKnownLocation(String provider) { try { - synchronized (mLocationListeners) { + synchronized (mLock) { return _getLastKnownLocationLocked(provider); } } catch (SecurityException se) { @@ -1532,7 +1488,7 @@ public class LocationManagerService extends ILocationManager.Stub private Location _getLastKnownLocationLocked(String provider) { checkPermissionsSafe(provider); - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); + LocationProviderProxy p = mProvidersByName.get(provider); if (p == null) { throw new IllegalArgumentException("provider=" + provider); } @@ -1576,79 +1532,34 @@ public class LocationManagerService extends ILocationManager.Stub return true; } - private void handleLocationChangedLocked(String provider) { + private void handleLocationChangedLocked(Location location) { + String provider = location.getProvider(); ArrayList records = mRecordsByProvider.get(provider); if (records == null || records.size() == 0) { return; } - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); + LocationProviderProxy p = mProvidersByName.get(provider); if (p == null) { return; } - // Get location object - Location loc = mLocationsByProvider.get(provider); - if (loc == null) { - loc = new Location(provider); - mLocationsByProvider.put(provider, loc); - } else { - loc.reset(); - } - - // Use the mock location if available - Location mockLoc = mMockProviderLocation.get(provider); - boolean locationValid; - if (mockLoc != null) { - locationValid = true; - loc.set(mockLoc); - } else { - locationValid = p.getLocation(loc); - } - // Update last known location for provider - if (locationValid) { - Location location = mLastKnownLocation.get(provider); - if (location == null) { - mLastKnownLocation.put(provider, new Location(loc)); - } else { - location.set(loc); - } - writeLastKnownLocationLocked(provider, loc); - - if (p instanceof INetworkLocationProvider) { - mWakeLockNetworkReceived = true; - } else if (p instanceof GpsLocationProvider) { - // Gps location received signal is in NetworkStateBroadcastReceiver - } + Location lastLocation = mLastKnownLocation.get(provider); + if (lastLocation == null) { + mLastKnownLocation.put(provider, new Location(location)); + } else { + lastLocation.set(location); } + writeLastKnownLocationLocked(provider, location); // Fetch latest status update time long newStatusUpdateTime = p.getStatusUpdateTime(); - // Override real time with mock time if present - Long mockStatusUpdateTime = mMockProviderStatusUpdateTime.get(provider); - if (mockStatusUpdateTime != null) { - newStatusUpdateTime = mockStatusUpdateTime.longValue(); - } - - // Get latest status + // Get latest status Bundle extras = new Bundle(); int status = p.getStatus(extras); - // Override status with mock status if present - Integer mockStatus = mMockProviderStatus.get(provider); - if (mockStatus != null) { - status = mockStatus.intValue(); - } - - // Override extras with mock extras if present - Bundle mockExtras = mMockProviderStatusExtras.get(provider); - if (mockExtras != null) { - extras.clear(); - extras.putAll(mockExtras); - } - ArrayList deadReceivers = null; // Broadcast location or status to all listeners @@ -1657,44 +1568,28 @@ public class LocationManagerService extends ILocationManager.Stub UpdateRecord r = records.get(i); Receiver receiver = r.mReceiver; - // Broadcast location only if it is valid - if (locationValid) { - HashMap map = mLastFixBroadcast.get(receiver); - if (map == null) { - map = new HashMap(); - mLastFixBroadcast.put(receiver, map); + Location lastLoc = r.mLastFixBroadcast; + if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { + if (lastLoc == null) { + lastLoc = new Location(location); + r.mLastFixBroadcast = lastLoc; + } else { + lastLoc.set(location); } - Location lastLoc = map.get(provider); - if ((lastLoc == null) || shouldBroadcastSafe(loc, lastLoc, r)) { - if (lastLoc == null) { - lastLoc = new Location(loc); - map.put(provider, lastLoc); - } else { - lastLoc.set(loc); - } - if (!receiver.callLocationChangedLocked(loc)) { - Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver); - if (deadReceivers == null) { - deadReceivers = new ArrayList(); - } - deadReceivers.add(receiver); + if (!receiver.callLocationChangedLocked(location)) { + Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver); + if (deadReceivers == null) { + deadReceivers = new ArrayList(); } + deadReceivers.add(receiver); } } - // Broadcast status message - HashMap statusMap = mLastStatusBroadcast.get(receiver); - if (statusMap == null) { - statusMap = new HashMap(); - mLastStatusBroadcast.put(receiver, statusMap); - } - long prevStatusUpdateTime = - (statusMap.get(provider) != null) ? statusMap.get(provider) : 0; - + long prevStatusUpdateTime = r.mLastStatusBroadcast; if ((newStatusUpdateTime > prevStatusUpdateTime) && (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { - statusMap.put(provider, newStatusUpdateTime); + r.mLastStatusBroadcast = newStatusUpdateTime; if (!receiver.callStatusChangedLocked(provider, status, extras)) { Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver); if (deadReceivers == null) { @@ -1719,70 +1614,28 @@ public class LocationManagerService extends ILocationManager.Stub @Override public void handleMessage(Message msg) { try { - if (msg.what == MESSAGE_HEARTBEAT) { - // log("LocationWorkerHandler: Heartbeat!"); + if (msg.what == MESSAGE_LOCATION_CHANGED) { + // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!"); + + synchronized (mLock) { + Location location = (Location) msg.obj; + + if (mCollector != null && + LocationManager.GPS_PROVIDER.equals(location.getProvider())) { + try { + mCollector.updateLocation(location); + } catch (RemoteException e) { + Log.w(TAG, "mCollector.updateLocation failed"); + mCollector = null; + } + } - synchronized (mLocationListeners) { - String provider = (String) msg.obj; + String provider = location.getProvider(); if (!isAllowedBySettingsLocked(provider)) { return; } - // Process the location fix if the screen is on or we're holding a wakelock - if (mScreenOn || (mWakeLockAcquireTime != 0)) { - handleLocationChangedLocked(provider); - } - - // If it continues to have listeners - ArrayList records = mRecordsByProvider.get(provider); - if (records != null && records.size() > 0) { - Message m = Message.obtain(this, MESSAGE_HEARTBEAT, provider); - sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); - } - - if ((mWakeLockAcquireTime != 0) && - (SystemClock.elapsedRealtime() - mWakeLockAcquireTime - > MAX_TIME_FOR_WAKE_LOCK)) { - - removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - - log("LocationWorkerHandler: Exceeded max time for wake lock"); - Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); - sendMessageAtFrontOfQueue(m); - - } else if (mWakeLockAcquireTime != 0 && - mWakeLockGpsReceived && mWakeLockNetworkReceived) { - - removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - - log("LocationWorkerHandler: Locations received."); - mWakeLockAcquireTime = 0; - Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); - sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK); - } - } - - } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) { - log("LocationWorkerHandler: Acquire"); - synchronized (mLocationListeners) { - acquireWakeLockLocked(); - } - } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) { - log("LocationWorkerHandler: Release"); - - // Update wakelock status so the next alarm is set before releasing wakelock - synchronized (mLocationListeners) { - updateWakelockStatusLocked(mScreenOn); - releaseWakeLockLocked(); - } - } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) { - synchronized (mLocationListeners) { - Log.d(TAG, "installing network location provider"); - INetworkLocationManager.InstallCallback callback = - (INetworkLocationManager.InstallCallback)msg.obj; - callback.installNetworkLocationProvider(LocationManagerService.this); + handleLocationChangedLocked(location); } } } catch (Exception e) { @@ -1792,159 +1645,14 @@ public class LocationManagerService extends ILocationManager.Stub } } - class CellLocationUpdater extends Thread { - CellLocation mNextLocation; - - CellLocationUpdater() { - super("CellLocationUpdater"); - } - - @Override - public void run() { - int curAsu = -1; - CellLocation curLocation = null; - - while (true) { - // See if there is more work to do... - synchronized (mLocationListeners) { - if (curLocation == mNextLocation) { - mCellLocationUpdater = null; - break; - } - - curLocation = mNextLocation; - if (curLocation == null) { - mCellLocationUpdater = null; - break; - } - - curAsu = mLastSignalStrength; - - mNextLocation = null; - } - - try { - // Gets cell state. This can block so must be done without - // locks held. - CellState cs = new CellState(mTelephonyManager, curLocation, curAsu); - - synchronized (mLocationListeners) { - mLastCellState = cs; - - cs.updateSignalStrength(mLastSignalStrength); - cs.updateRadioType(mLastRadioType); - - // Notify collector - if (mCollector != null) { - mCollector.updateCellState(cs); - } - - // Updates providers - List providers = LocationProviderImpl.getProviders(); - for (LocationProviderImpl provider : providers) { - if (provider.requiresCell()) { - provider.updateCellState(cs); - } - } - } - } catch (RuntimeException e) { - Log.e(TAG, "Exception in PhoneStateListener.onCellLocationChanged:", e); - } - } - } - } - - CellLocationUpdater mCellLocationUpdater = null; - CellState mLastCellState = null; - int mLastSignalStrength = -1; - int mLastRadioType = -1; - - PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - - @Override - public void onCellLocationChanged(CellLocation cellLocation) { - synchronized (mLocationListeners) { - if (mCellLocationUpdater == null) { - mCellLocationUpdater = new CellLocationUpdater(); - mCellLocationUpdater.start(); - } - mCellLocationUpdater.mNextLocation = cellLocation; - } - } - - @Override - public void onSignalStrengthChanged(int asu) { - synchronized (mLocationListeners) { - mLastSignalStrength = asu; - - if (mLastCellState != null) { - mLastCellState.updateSignalStrength(asu); - } - } - } - + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override - public void onDataConnectionStateChanged(int state) { - synchronized (mLocationListeners) { - // Get radio type - int radioType = mTelephonyManager.getNetworkType(); - if (radioType == TelephonyManager.NETWORK_TYPE_GPRS || - radioType == TelephonyManager.NETWORK_TYPE_EDGE) { - radioType = CellState.RADIO_TYPE_GPRS; - } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) { - radioType = CellState.RADIO_TYPE_WCDMA; - } - mLastRadioType = radioType; - - if (mLastCellState != null) { - mLastCellState.updateRadioType(radioType); - } - } - } - }; - - private class PowerStateBroadcastReceiver extends BroadcastReceiver { - @Override public void onReceive(Context context, Intent intent) { + public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (action.equals(ALARM_INTENT)) { - synchronized (mLocationListeners) { - log("PowerStateBroadcastReceiver: Alarm received"); - mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - // Have to do this immediately, rather than posting a - // message, so we execute our code while the system - // is holding a wake lock until the alarm broadcast - // is finished. - acquireWakeLockLocked(); - } - - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - log("PowerStateBroadcastReceiver: Screen off"); - synchronized (mLocationListeners) { - updateWakelockStatusLocked(false); - } - - } else if (action.equals(Intent.ACTION_SCREEN_ON)) { - log("PowerStateBroadcastReceiver: Screen on"); - synchronized (mLocationListeners) { - updateWakelockStatusLocked(true); - } - - } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - log("PowerStateBroadcastReceiver: Battery changed"); - synchronized (mLocationListeners) { - int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100); - int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0); - boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0; - - // Notify collector battery state - if (mCollector != null) { - mCollector.updateBatteryState(scale, level, plugged); - } - } - } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) + if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) { - synchronized (mLocationListeners) { + synchronized (mLock) { int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); if (uid >= 0) { ArrayList removedRecs = null; @@ -1984,32 +1692,6 @@ public class LocationManagerService extends ILocationManager.Stub } } } - } - } - } - - private class NetworkStateBroadcastReceiver extends BroadcastReceiver { - @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - - List wifiScanResults = mWifiManager.getScanResults(); - - if (wifiScanResults == null) { - return; - } - - // Notify provider and collector of Wifi scan results - synchronized (mLocationListeners) { - if (mCollector != null) { - mCollector.updateWifiScanResults(wifiScanResults); - } - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); - } - } - } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); @@ -2020,484 +1702,92 @@ public class LocationManagerService extends ILocationManager.Stub } // Notify location providers of current network state - synchronized (mLocationListeners) { - List providers = LocationProviderImpl.getProviders(); - for (LocationProviderImpl provider : providers) { + synchronized (mLock) { + for (int i = mProviders.size() - 1; i >= 0; i--) { + LocationProviderProxy provider = mProviders.get(i); if (provider.requiresNetwork()) { provider.updateNetworkState(mNetworkState); } } } - - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN); - - if (state == WifiManager.WIFI_STATE_ENABLED) { - mWifiEnabled = true; - } else if (state == WifiManager.WIFI_STATE_DISABLED) { - mWifiEnabled = false; - } else { - return; - } - - // Notify network provider of current wifi enabled state - synchronized (mLocationListeners) { - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled); - } - } - - } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) { - - final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, - false); - - synchronized (mLocationListeners) { - if (enabled) { - updateReportedGpsLocked(); - mGpsNavigating = true; - } else { - reportStopGpsLocked(); - mGpsNavigating = false; - // When GPS is disabled, we are OK to release wake-lock - mWakeLockGpsReceived = true; - } - } } - } - } + }; // Wake locks - private void updateWakelockStatusLocked(boolean screenOn) { - log("updateWakelockStatus(): " + screenOn); - - long callerId = Binder.clearCallingIdentity(); - - boolean needsLock = false; - long minTime = Integer.MAX_VALUE; - - if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) { - needsLock = true; - minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime); - } - - if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) { - needsLock = true; - minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime); - if (screenOn) { - startGpsLocked(); - } else if (mScreenOn && !screenOn) { - // We just turned the screen off so stop navigating - stopGpsLocked(); - } - } - - mScreenOn = screenOn; - - PendingIntent sender = - PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0); - - // Cancel existing alarm - log("Cancelling existing alarm"); - mAlarmManager.cancel(sender); - - if (needsLock && !mScreenOn) { - long now = SystemClock.elapsedRealtime(); - mAlarmManager.set( - AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender); - mAlarmInterval = minTime; - log("Creating a new wakelock alarm with minTime = " + minTime); - } else { - log("No need for alarm"); - mAlarmInterval = -1; - - // Clear out existing wakelocks - mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - releaseWakeLockLocked(); - } - Binder.restoreCallingIdentity(callerId); - } - - private void acquireWakeLockLocked() { - try { - acquireWakeLockXLocked(); - } 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 acquireWakeLockXLocked() { - if (mWakeLock.isHeld()) { - log("Must release wakelock before acquiring"); - mWakeLockAcquireTime = 0; - mWakeLock.release(); - } - - boolean networkActive = (mNetworkLocationProvider != null) - && mNetworkLocationProvider.isLocationTracking(); - boolean gpsActive = (mGpsLocationProvider != null) - && mGpsLocationProvider.isLocationTracking(); - - boolean needsLock = networkActive || gpsActive; - if (!needsLock) { - log("No need for Lock!"); - return; - } - - mWakeLockGpsReceived = !gpsActive; - mWakeLockNetworkReceived = !networkActive; - - // Acquire wake lock - mWakeLock.acquire(); - mWakeLockAcquireTime = SystemClock.elapsedRealtime(); - log("Acquired wakelock"); - - // Start the gps provider - startGpsLocked(); - - // Acquire cell lock - if (mCellWakeLockAcquired) { - // Lock is already acquired - } else if (!mWakeLockNetworkReceived) { - mTelephonyManager.enableLocationUpdates(); - mCellWakeLockAcquired = true; - } else { - mCellWakeLockAcquired = false; - } - - // Notify NetworkLocationProvider - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); - } - - // Acquire wifi lock - WifiManager.WifiLock wifiLock = getWifiWakelockLocked(); - if (wifiLock != null) { - if (mWifiWakeLockAcquired) { - // Lock is already acquired - } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) { - wifiLock.acquire(); - mWifiWakeLockAcquired = true; - } else { - mWifiWakeLockAcquired = false; - Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock"); - } - } - } - - private boolean reportGpsUidLocked(int curSeq, int nextSeq, int uid) { - int seq = mReportedGpsUids.get(uid, -1); - if (seq == curSeq) { - // Already reported; propagate to next sequence. - mReportedGpsUids.put(uid, nextSeq); - return true; - } else if (seq != nextSeq) { - try { - // New UID; report it. - mBatteryStats.noteStartGps(uid); - mReportedGpsUids.put(uid, nextSeq); - return true; - } catch (RemoteException e) { - } - } - return false; - } - - private void updateReportedGpsLocked() { - if (mGpsLocationProvider == null) { - return; - } - - final String name = mGpsLocationProvider.getName(); - final int curSeq = mReportedGpsSeq; - final int nextSeq = (curSeq+1) >= 0 ? (curSeq+1) : 0; - mReportedGpsSeq = nextSeq; - - ArrayList urs = mRecordsByProvider.get(name); - int num = 0; - final int N = urs.size(); - for (int i=0; i=0; i--) { - if (mReportedGpsUids.valueAt(i) != nextSeq) { - try { - mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i)); - } catch (RemoteException e) { - } - mReportedGpsUids.removeAt(i); - } - } - } - } - - private void reportStopGpsLocked() { - int curSeq = mReportedGpsSeq; - for (int i=mReportedGpsUids.size()-1; i>=0; i--) { - if (mReportedGpsUids.valueAt(i) == curSeq) { + private void incrementPendingBroadcasts() { + synchronized (mWakeLock) { + if (mPendingBroadcasts++ == 0) { try { - mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i)); - } catch (RemoteException e) { + mWakeLock.acquire(); + log("Acquired wakelock"); + } 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); } } } - curSeq++; - if (curSeq < 0) curSeq = 0; - mReportedGpsSeq = curSeq; - mReportedGpsUids.clear(); - } - - private void startGpsLocked() { - boolean gpsActive = (mGpsLocationProvider != null) - && mGpsLocationProvider.isLocationTracking(); - if (gpsActive) { - mGpsLocationProvider.startNavigating(); - } - } - - private void stopGpsLocked() { - boolean gpsActive = mGpsLocationProvider != null - && mGpsLocationProvider.isLocationTracking(); - if (gpsActive) { - mGpsLocationProvider.stopNavigating(); - } - } - - private void releaseWakeLockLocked() { - try { - releaseWakeLockXLocked(); - } 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 releaseWakeLockXLocked() { - // Release wifi lock - WifiManager.WifiLock wifiLock = getWifiWakelockLocked(); - if (wifiLock != null) { - if (mWifiWakeLockAcquired) { - wifiLock.release(); - mWifiWakeLockAcquired = false; + private void decrementPendingBroadcasts() { + synchronized (mWakeLock) { + if (--mPendingBroadcasts == 0) { + try { + // Release wake lock + if (mWakeLock.isHeld()) { + mWakeLock.release(); + log("Released wakelock"); + } else { + log("Can't release wakelock again!"); + } + } 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); + } } } - - if (!mScreenOn) { - // Stop the gps - stopGpsLocked(); - } - - // Release cell lock - if (mCellWakeLockAcquired) { - mTelephonyManager.disableLocationUpdates(); - mCellWakeLockAcquired = false; - } - - // Notify NetworkLocationProvider - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); - } - - // Release wake lock - mWakeLockAcquireTime = 0; - if (mWakeLock.isHeld()) { - log("Released wakelock"); - mWakeLock.release(); - } else { - log("Can't release wakelock again!"); - } } // Geocoder public String getFromLocation(double latitude, double longitude, int maxResults, - String language, String country, String variant, String appName, List

        addrs) { - synchronized (mLocationListeners) { - if (mNetworkLocationInterface != null) { - return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults, - language, country, variant, appName, addrs); - } else { - return null; + String language, String country, String variant, String appName, List
        addrs) { + if (mGeocodeProvider != null) { + try { + return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country, + variant, appName, addrs); + } catch (RemoteException e) { + Log.e(TAG, "getFromLocation failed", e); + mGeocodeProvider = null; } } + return null; } + public String getFromLocationName(String locationName, - double lowerLeftLatitude, double lowerLeftLongitude, - double upperRightLatitude, double upperRightLongitude, int maxResults, - String language, String country, String variant, String appName, List
        addrs) { - synchronized (mLocationListeners) { - if (mNetworkLocationInterface != null) { - return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude, - lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults, - language, country, variant, appName, addrs); - } else { - return null; + double lowerLeftLatitude, double lowerLeftLongitude, + double upperRightLatitude, double upperRightLongitude, int maxResults, + String language, String country, String variant, String appName, List
        addrs) { + + if (mGeocodeProvider != null) { + try { + return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, + lowerLeftLongitude, upperRightLatitude, upperRightLongitude, + maxResults, language, country, variant, appName, addrs); + } catch (RemoteException e) { + Log.e(TAG, "getFromLocationName failed", e); + mGeocodeProvider = null; } } + return null; } // Mock Providers - class MockProvider extends LocationProviderImpl { - boolean mRequiresNetwork; - boolean mRequiresSatellite; - boolean mRequiresCell; - boolean mHasMonetaryCost; - boolean mSupportsAltitude; - boolean mSupportsSpeed; - boolean mSupportsBearing; - int mPowerRequirement; - int mAccuracy; - - public MockProvider(String name, boolean requiresNetwork, boolean requiresSatellite, - boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, - boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { - super(name); - - mRequiresNetwork = requiresNetwork; - mRequiresSatellite = requiresSatellite; - mRequiresCell = requiresCell; - mHasMonetaryCost = hasMonetaryCost; - mSupportsAltitude = supportsAltitude; - mSupportsBearing = supportsBearing; - mSupportsSpeed = supportsSpeed; - mPowerRequirement = powerRequirement; - mAccuracy = accuracy; - } - - @Override - public void disable() { - String name = getName(); - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - mEnabledProviders.remove(name); - mDisabledProviders.add(name); - } - } - - @Override - public void enable() { - String name = getName(); - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - mEnabledProviders.add(name); - mDisabledProviders.remove(name); - } - } - - @Override - public boolean getLocation(Location l) { - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - Location loc = mMockProviderLocation.get(getName()); - if (loc == null) { - return false; - } - l.set(loc); - return true; - } - } - - @Override - public int getStatus(Bundle extras) { - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - String name = getName(); - Integer s = mMockProviderStatus.get(name); - int status = (s == null) ? AVAILABLE : s.intValue(); - Bundle newExtras = mMockProviderStatusExtras.get(name); - if (newExtras != null) { - extras.clear(); - extras.putAll(newExtras); - } - return status; - } - } - - @Override - public boolean isEnabled() { - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - return mEnabledProviders.contains(getName()); - } - } - - @Override - public int getAccuracy() { - return mAccuracy; - } - - @Override - public int getPowerRequirement() { - return mPowerRequirement; - } - - @Override - public boolean hasMonetaryCost() { - return mHasMonetaryCost; - } - - @Override - public boolean requiresCell() { - return mRequiresCell; - } - - @Override - public boolean requiresNetwork() { - return mRequiresNetwork; - } - - @Override - public boolean requiresSatellite() { - return mRequiresSatellite; - } - - @Override - public boolean supportsAltitude() { - return mSupportsAltitude; - } - - @Override - public boolean supportsBearing() { - return mSupportsBearing; - } - - @Override - public boolean supportsSpeed() { - return mSupportsSpeed; - } - } - private void checkMockPermissionsSafe() { boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; @@ -2516,60 +1806,75 @@ public class LocationManagerService extends ILocationManager.Stub boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite, + synchronized (mLock) { + MockProvider provider = new MockProvider(name, this, + requiresNetwork, requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement, accuracy); - if (LocationProviderImpl.getProvider(name) != null) { + if (mProvidersByName.get(name) != null) { throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); } - LocationProviderImpl.addProvider(provider); + + // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required + long identity = Binder.clearCallingIdentity(); + addProvider(new LocationProviderProxy(name, provider)); + mMockProviders.put(name, provider); updateProvidersLocked(); + Binder.restoreCallingIdentity(identity); } } public void removeTestProvider(String provider) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p == null) { + synchronized (mLock) { + MockProvider mockProvider = mMockProviders.get(provider); + if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } - LocationProviderImpl.removeProvider(p); + removeProvider(mProvidersByName.get(provider)); + mMockProviders.remove(mockProvider); updateProvidersLocked(); } } public void setTestProviderLocation(String provider, Location loc) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { + synchronized (mLock) { + MockProvider mockProvider = mMockProviders.get(provider); + if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } - mMockProviderLocation.put(provider, loc); + // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required + long identity = Binder.clearCallingIdentity(); + mockProvider.setLocation(loc); + Binder.restoreCallingIdentity(identity); } } public void clearTestProviderLocation(String provider) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { + synchronized (mLock) { + MockProvider mockProvider = mMockProviders.get(provider); + if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } - mMockProviderLocation.remove(provider); + mockProvider.clearLocation(); } } public void setTestProviderEnabled(String provider, boolean enabled) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { + synchronized (mLock) { + MockProvider mockProvider = mMockProviders.get(provider); + if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } if (enabled) { + mockProvider.enable(); mEnabledProviders.add(provider); mDisabledProviders.remove(provider); } else { + mockProvider.disable(); mEnabledProviders.remove(provider); mDisabledProviders.add(provider); } @@ -2579,8 +1884,9 @@ public class LocationManagerService extends ILocationManager.Stub public void clearTestProviderEnabled(String provider) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { + synchronized (mLock) { + MockProvider mockProvider = mMockProviders.get(provider); + if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } mEnabledProviders.remove(provider); @@ -2591,25 +1897,23 @@ public class LocationManagerService extends ILocationManager.Stub public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { + synchronized (mLock) { + MockProvider mockProvider = mMockProviders.get(provider); + if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } - mMockProviderStatus.put(provider, new Integer(status)); - mMockProviderStatusExtras.put(provider, extras); - mMockProviderStatusUpdateTime.put(provider, new Long(updateTime)); + mockProvider.setStatus(status, extras, updateTime); } } public void clearTestProviderStatus(String provider) { checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { + synchronized (mLock) { + MockProvider mockProvider = mMockProviders.get(provider); + if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } - mMockProviderStatus.remove(provider); - mMockProviderStatusExtras.remove(provider); - mMockProviderStatusUpdateTime.remove(provider); + mockProvider.clearStatus(); } } @@ -2622,63 +1926,29 @@ public class LocationManagerService extends ILocationManager.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump AlarmManager from from pid=" + pw.println("Permission Denial: can't dump LocationManagerService from from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); return; } - synchronized (mLocationListeners) { + synchronized (mLock) { pw.println("Current Location Manager state:"); pw.println(" sProvidersLoaded=" + sProvidersLoaded); - pw.println(" mGpsLocationProvider=" + mGpsLocationProvider); - pw.println(" mGpsNavigating=" + mGpsNavigating); - pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider); - pw.println(" mNetworkLocationInterface=" + mNetworkLocationInterface); - pw.println(" mLastSignalStrength=" + mLastSignalStrength - + " mLastRadioType=" + mLastRadioType); - pw.println(" mCellLocationUpdater=" + mCellLocationUpdater); - pw.println(" mLastCellState=" + mLastCellState); pw.println(" mCollector=" + mCollector); - pw.println(" mAlarmInterval=" + mAlarmInterval - + " mScreenOn=" + mScreenOn - + " mWakeLockAcquireTime=" + mWakeLockAcquireTime); - pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived - + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived); - pw.println(" mWifiWakeLockAcquired=" + mWifiWakeLockAcquired - + " mCellWakeLockAcquired=" + mCellWakeLockAcquired); pw.println(" Listeners:"); - int N = mListeners.size(); + int N = mReceivers.size(); for (int i=0; i> i - : mLocationListeners.entrySet()) { - pw.println(" " + i.getKey() + ":"); - for (Map.Entry j : i.getValue().entrySet()) { + for (Receiver i : mReceivers.values()) { + pw.println(" " + i + ":"); + for (Map.Entry j : i.mUpdateRecords.entrySet()) { pw.println(" " + j.getKey() + ":"); j.getValue().dump(pw, " "); } } - pw.println(" Last Fix Broadcasts:"); - for (Map.Entry> i - : mLastFixBroadcast.entrySet()) { - pw.println(" " + i.getKey() + ":"); - for (Map.Entry j : i.getValue().entrySet()) { - pw.println(" " + j.getKey() + ":"); - j.getValue().dump(new PrintWriterPrinter(pw), " "); - } - } - pw.println(" Last Status Broadcasts:"); - for (Map.Entry> i - : mLastStatusBroadcast.entrySet()) { - pw.println(" " + i.getKey() + ":"); - for (Map.Entry j : i.getValue().entrySet()) { - pw.println(" " + j.getKey() + " -> 0x" - + Long.toHexString(j.getValue())); - } - } pw.println(" Records by Provider:"); for (Map.Entry> i : mRecordsByProvider.entrySet()) { @@ -2688,12 +1958,6 @@ public class LocationManagerService extends ILocationManager.Stub j.dump(pw, " "); } } - pw.println(" Locations by Provider:"); - for (Map.Entry i - : mLocationsByProvider.entrySet()) { - pw.println(" " + i.getKey() + ":"); - i.getValue().dump(new PrintWriterPrinter(pw), " "); - } pw.println(" Last Known Locations:"); for (Map.Entry i : mLastKnownLocation.entrySet()) { @@ -2715,6 +1979,7 @@ public class LocationManagerService extends ILocationManager.Stub i.dump(pw, " "); } } + pw.println(" mProximityReceiver=" + mProximityReceiver); pw.println(" mProximityListener=" + mProximityListener); if (mEnabledProviders.size() > 0) { pw.println(" Enabled Providers:"); @@ -2733,42 +1998,9 @@ public class LocationManagerService extends ILocationManager.Stub if (mMockProviders.size() > 0) { pw.println(" Mock Providers:"); for (Map.Entry i : mMockProviders.entrySet()) { - pw.println(" " + i.getKey() + " -> " + i.getValue()); - } - } - if (mMockProviderLocation.size() > 0) { - pw.println(" Mock Provider Location:"); - for (Map.Entry i : mMockProviderLocation.entrySet()) { - pw.println(" " + i.getKey() + ":"); - i.getValue().dump(new PrintWriterPrinter(pw), " "); - } - } - if (mMockProviderStatus.size() > 0) { - pw.println(" Mock Provider Status:"); - for (Map.Entry i : mMockProviderStatus.entrySet()) { - pw.println(" " + i.getKey() + " -> 0x" - + Integer.toHexString(i.getValue())); - } - } - if (mMockProviderStatusExtras.size() > 0) { - pw.println(" Mock Provider Status Extras:"); - for (Map.Entry i : mMockProviderStatusExtras.entrySet()) { - pw.println(" " + i.getKey() + " -> " + i.getValue()); - } - } - if (mMockProviderStatusUpdateTime.size() > 0) { - pw.println(" Mock Provider Status Update Time:"); - for (Map.Entry i : mMockProviderStatusUpdateTime.entrySet()) { - pw.println(" " + i.getKey() + " -> " + i.getValue()); + i.getValue().dump(pw, " "); } } - pw.println(" Reported GPS UIDs @ seq " + mReportedGpsSeq + ":"); - N = mReportedGpsUids.size(); - for (int i=0; i filterEnabled(List resolveInfoList) { @@ -3064,11 +3074,12 @@ class PackageManagerService extends IPackageManager.Stub { } @Override - protected void dumpFilter(Printer out, String prefix, + protected void dumpFilter(PrintWriter out, String prefix, PackageParser.ServiceIntentInfo filter) { - out.println(prefix - + Integer.toHexString(System.identityHashCode(filter.service)) - + " " + filter.service.component.flattenToShortString()); + out.print(prefix); out.print( + Integer.toHexString(System.identityHashCode(filter.service))); + out.print(' '); + out.println(filter.service.componentShortName); } // List filterEnabled(List resolveInfoList) { @@ -3220,20 +3231,27 @@ class PackageManagerService extends IPackageManager.Stub { private final String mRootDir; private final boolean mIsRom; } - + /* Called when a downloaded package installation has been confirmed by the user */ public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags) { + installPackage(packageURI, observer, flags, null); + } + + /* Called when a downloaded package installation has been confirmed by the user */ + public void installPackage( + final Uri packageURI, final IPackageInstallObserver observer, final int flags, + final String installerPackageName) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INSTALL_PACKAGES, null); - + // Queue up an async operation since the package installation may take a little while. mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); PackageInstalledInfo res; synchronized (mInstallLock) { - res = installPackageLI(packageURI, flags, true); + res = installPackageLI(packageURI, flags, true, installerPackageName); } if (observer != null) { try { @@ -3281,7 +3299,7 @@ class PackageManagerService extends IPackageManager.Stub { File tmpPackageFile, String destFilePath, File destPackageFile, File destResourceFile, PackageParser.Package pkg, boolean forwardLocked, boolean newInstall, - PackageInstalledInfo res) { + String installerPackageName, PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists(); res.name = pkgName; @@ -3317,7 +3335,8 @@ class PackageManagerService extends IPackageManager.Stub { destResourceFile, pkg, newPackage, true, - forwardLocked, + forwardLocked, + installerPackageName, res); // delete the partially installed application. the data directory will have to be // restored if it was already existing @@ -3338,26 +3357,27 @@ class PackageManagerService extends IPackageManager.Stub { File tmpPackageFile, String destFilePath, File destPackageFile, File destResourceFile, PackageParser.Package pkg, boolean forwardLocked, boolean newInstall, - PackageInstalledInfo res) { - PackageParser.Package deletedPackage; + String installerPackageName, PackageInstalledInfo res) { + + PackageParser.Package oldPackage; // First find the old package info and check signatures synchronized(mPackages) { - deletedPackage = mPackages.get(pkgName); - if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) { + oldPackage = mPackages.get(pkgName); + if(checkSignaturesLP(pkg, oldPackage) != PackageManager.SIGNATURE_MATCH) { res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; return; } } - boolean sysPkg = ((deletedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); if(sysPkg) { - replaceSystemPackageLI(deletedPackage, + replaceSystemPackageLI(oldPackage, tmpPackageFile, destFilePath, destPackageFile, destResourceFile, pkg, forwardLocked, - newInstall, res); + newInstall, installerPackageName, res); } else { - replaceNonSystemPackageLI(deletedPackage, tmpPackageFile, destFilePath, + replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath, destPackageFile, destResourceFile, pkg, forwardLocked, - newInstall, res); + newInstall, installerPackageName, res); } } @@ -3365,12 +3385,18 @@ class PackageManagerService extends IPackageManager.Stub { File tmpPackageFile, String destFilePath, File destPackageFile, File destResourceFile, PackageParser.Package pkg, boolean forwardLocked, boolean newInstall, - PackageInstalledInfo res) { + String installerPackageName, PackageInstalledInfo res) { PackageParser.Package newPackage = null; String pkgName = deletedPackage.packageName; boolean deletedPkg = true; boolean updatedSettings = false; - int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE; + + String oldInstallerPackageName = null; + synchronized (mPackages) { + oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName); + } + + int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING; // First delete the existing package while retaining the data directory if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, res.removedInfo)) { @@ -3398,6 +3424,7 @@ class PackageManagerService extends IPackageManager.Stub { newPackage, true, forwardLocked, + installerPackageName, res); updatedSettings = true; } @@ -3441,8 +3468,8 @@ class PackageManagerService extends IPackageManager.Stub { installPackageLI( Uri.fromFile(new File(deletedPackage.mPath)), isForwardLocked(deletedPackage) - ? PackageManager.FORWARD_LOCK_PACKAGE - : 0, false); + ? PackageManager.INSTALL_FORWARD_LOCK + : 0, false, oldInstallerPackageName); } } } @@ -3451,10 +3478,10 @@ class PackageManagerService extends IPackageManager.Stub { File tmpPackageFile, String destFilePath, File destPackageFile, File destResourceFile, PackageParser.Package pkg, boolean forwardLocked, boolean newInstall, - PackageInstalledInfo res) { + String installerPackageName, PackageInstalledInfo res) { PackageParser.Package newPackage = null; boolean updatedSettings = false; - int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE | + int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING | PackageParser.PARSE_IS_SYSTEM; String packageName = deletedPackage.packageName; res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; @@ -3501,7 +3528,8 @@ class PackageManagerService extends IPackageManager.Stub { destResourceFile, pkg, newPackage, true, - forwardLocked, + forwardLocked, + installerPackageName, res); updatedSettings = true; } @@ -3528,6 +3556,8 @@ class PackageManagerService extends IPackageManager.Stub { synchronized(mPackages) { if(updatedSettings) { mSettings.enableSystemPackageLP(packageName); + mSettings.setInstallerPackageName(packageName, + oldPkgSetting.installerPackageName); } mSettings.writeLP(); } @@ -3541,7 +3571,7 @@ class PackageManagerService extends IPackageManager.Stub { PackageParser.Package newPackage, boolean replacingExistingPackage, boolean forwardLocked, - PackageInstalledInfo res) { + String installerPackageName, PackageInstalledInfo res) { synchronized (mPackages) { //write settings. the installStatus will be incomplete at this stage. //note that the new package setting would have already been @@ -3588,6 +3618,7 @@ class PackageManagerService extends IPackageManager.Stub { res.uid = newPackage.applicationInfo.uid; res.pkg = newPackage; mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE); + mSettings.setInstallerPackageName(pkgName, installerPackageName); res.returnCode = PackageManager.INSTALL_SUCCEEDED; //to update install status mSettings.writeLP(); @@ -3595,7 +3626,7 @@ class PackageManagerService extends IPackageManager.Stub { } private PackageInstalledInfo installPackageLI(Uri pPackageURI, - int pFlags, boolean newInstall) { + int pFlags, boolean newInstall, String installerPackageName) { File tmpPackageFile = null; String pkgName = null; boolean forwardLocked = false; @@ -3666,13 +3697,13 @@ class PackageManagerService extends IPackageManager.Stub { res.name = pkgName; //initialize some variables before installing pkg final String pkgFileName = pkgName + ".apk"; - final File destDir = ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) + final File destDir = ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) ? mDrmAppPrivateInstallDir : mAppInstallDir; final File destPackageFile = new File(destDir, pkgFileName); final String destFilePath = destPackageFile.getAbsolutePath(); File destResourceFile; - if ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { + if ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) { final String publicZipFileName = pkgName + ".zip"; destResourceFile = new File(mAppInstallDir, publicZipFileName); forwardLocked = true; @@ -3684,13 +3715,19 @@ class PackageManagerService extends IPackageManager.Stub { parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(tmpPackageFile.getPath()); pp.setSeparateProcesses(mSeparateProcesses); - pp.setSdkVersion(mSdkVersion); + pp.setSdkVersion(mSdkVersion, mSdkCodename); final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, destPackageFile.getAbsolutePath(), mMetrics, parseFlags); if (pkg == null) { res.returnCode = pp.getParseError(); break main_flow; } + if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) { + if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) { + res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY; + break main_flow; + } + } if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { res.returnCode = pp.getParseError(); break main_flow; @@ -3698,7 +3735,7 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { //check if installing already existing package - if ((pFlags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0 + if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0 && mPackages.containsKey(pkgName)) { replacingExistingPackage = true; } @@ -3708,13 +3745,13 @@ class PackageManagerService extends IPackageManager.Stub { replacePackageLI(pkgName, tmpPackageFile, destFilePath, destPackageFile, destResourceFile, - pkg, forwardLocked, newInstall, + pkg, forwardLocked, newInstall, installerPackageName, res); } else { installNewPackageLI(pkgName, tmpPackageFile, destFilePath, destPackageFile, destResourceFile, - pkg, forwardLocked, newInstall, + pkg, forwardLocked, newInstall, installerPackageName, res); } } finally { @@ -3994,7 +4031,7 @@ class PackageManagerService extends IPackageManager.Stub { * Tries to delete system package. */ private boolean deleteSystemPackageLI(PackageParser.Package p, - boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { + int flags, PackageRemovedInfo outInfo) { ApplicationInfo applicationInfo = p.applicationInfo; //applicable for non-partially installed applications only if (applicationInfo == null) { @@ -4016,6 +4053,19 @@ class PackageManagerService extends IPackageManager.Stub { } // Delete the updated package outInfo.isRemovedPackageSystemUpdate = true; + boolean deleteCodeAndResources = false; + if (ps.versionCode < p.mVersionCode) { + // Delete code and resources for downgrades + deleteCodeAndResources = true; + if ((flags & PackageManager.DONT_DELETE_DATA) == 0) { + flags &= ~PackageManager.DONT_DELETE_DATA; + } + } else { + // Preserve data by setting flag + if ((flags & PackageManager.DONT_DELETE_DATA) == 0) { + flags |= PackageManager.DONT_DELETE_DATA; + } + } boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo); if (!ret) { return false; @@ -4039,6 +4089,28 @@ class PackageManagerService extends IPackageManager.Stub { return true; } + private void deletePackageResourcesLI(String packageName, + String sourceDir, String publicSourceDir) { + File sourceFile = new File(sourceDir); + if (!sourceFile.exists()) { + Log.w(TAG, "Package source " + sourceDir + " does not exist."); + } + // Delete application's code and resources + sourceFile.delete(); + final File publicSourceFile = new File(publicSourceDir); + if (publicSourceFile.exists()) { + publicSourceFile.delete(); + } + if (mInstaller != null) { + int retCode = mInstaller.rmdex(sourceFile.toString()); + if (retCode < 0) { + Log.w(TAG, "Couldn't remove dex file for package: " + + packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode); + // we don't consider this to be a failure of the core package deletion + } + } + } + private boolean deleteInstalledPackageLI(PackageParser.Package p, boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { ApplicationInfo applicationInfo = p.applicationInfo; @@ -4046,11 +4118,6 @@ class PackageManagerService extends IPackageManager.Stub { 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."); - } outInfo.uid = applicationInfo.uid; // Delete package data from internal structures and also remove data if flag is set @@ -4058,19 +4125,8 @@ class PackageManagerService extends IPackageManager.Stub { // Delete application code and resources if (deleteCodeAndResources) { - sourceFile.delete(); - final File publicSourceFile = new File(applicationInfo.publicSourceDir); - if (publicSourceFile.exists()) { - publicSourceFile.delete(); - } - if (mInstaller != null) { - int retCode = mInstaller.rmdex(sourceFile.toString()); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove dex file for package: " - + p.packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode); - // we don't consider this to be a failure of the core package deletion - } - } + deletePackageResourcesLI(applicationInfo.packageName, + applicationInfo.sourceDir, applicationInfo.publicSourceDir); } return true; } @@ -4118,7 +4174,7 @@ class PackageManagerService extends IPackageManager.Stub { 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); + return deleteSystemPackageLI(p, flags, outInfo); } Log.i(TAG, "Removing non-system package:"+p.packageName); return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo); @@ -4513,6 +4569,16 @@ class PackageManagerService extends IPackageManager.Stub { } } + public String getInstallerPackageName(String packageName) { + synchronized (mPackages) { + PackageSetting pkg = mSettings.mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + return pkg.installerPackageName; + } + } + public int getApplicationEnabledSetting(String appPackageName) { synchronized (mPackages) { PackageSetting pkg = mSettings.mPackages.get(appPackageName); @@ -4578,80 +4644,83 @@ class PackageManagerService extends IPackageManager.Stub { return; } - Printer printer = new PrintWriterPrinter(pw); synchronized (mPackages) { pw.println("Activity Resolver Table:"); - mActivities.dump(printer, " "); + mActivities.dump(pw, " "); pw.println(" "); pw.println("Receiver Resolver Table:"); - mReceivers.dump(printer, " "); + mReceivers.dump(pw, " "); pw.println(" "); pw.println("Service Resolver Table:"); - mServices.dump(printer, " "); + mServices.dump(pw, " "); pw.println(" "); pw.println("Preferred Activities:"); - mSettings.mPreferredActivities.dump(printer, " "); + mSettings.mPreferredActivities.dump(pw, " "); pw.println(" "); pw.println("Preferred Packages:"); { for (PackageSetting ps : mSettings.mPreferredPackages) { - pw.println(" " + ps.name); + pw.print(" "); pw.println(ps.name); } } pw.println(" "); pw.println("Permissions:"); { for (BasePermission p : mSettings.mPermissions.values()) { - pw.println(" Permission [" + p.name + "] (" - + Integer.toHexString(System.identityHashCode(p)) - + "):"); - pw.println(" sourcePackage=" + p.sourcePackage); - pw.println(" uid=" + p.uid - + " gids=" + arrayToString(p.gids) - + " type=" + p.type); + pw.print(" Permission ["); pw.print(p.name); pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(p))); + pw.println("):"); + pw.print(" sourcePackage="); pw.println(p.sourcePackage); + pw.print(" uid="); pw.print(p.uid); + pw.print(" gids="); pw.print(arrayToString(p.gids)); + pw.print(" type="); pw.println(p.type); } } pw.println(" "); pw.println("Packages:"); { for (PackageSetting ps : mSettings.mPackages.values()) { - pw.println(" Package [" + ps.name + "] (" - + Integer.toHexString(System.identityHashCode(ps)) - + "):"); - pw.println(" userId=" + ps.userId - + " gids=" + arrayToString(ps.gids)); - pw.println(" sharedUser=" + ps.sharedUser); - pw.println(" pkg=" + ps.pkg); - pw.println(" codePath=" + ps.codePathString); - pw.println(" resourcePath=" + ps.resourcePathString); + pw.print(" Package ["); pw.print(ps.name); pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(ps))); + pw.println("):"); + pw.print(" userId="); pw.print(ps.userId); + pw.print(" gids="); pw.println(arrayToString(ps.gids)); + pw.print(" sharedUser="); pw.println(ps.sharedUser); + pw.print(" pkg="); pw.println(ps.pkg); + pw.print(" codePath="); pw.println(ps.codePathString); + pw.print(" resourcePath="); pw.println(ps.resourcePathString); if (ps.pkg != null) { - pw.println(" dataDir=" + ps.pkg.applicationInfo.dataDir); + pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); } - pw.println(" timeStamp=" + ps.getTimeStampStr()); - pw.println(" signatures=" + ps.signatures); - pw.println(" permissionsFixed=" + ps.permissionsFixed - + " pkgFlags=0x" + Integer.toHexString(ps.pkgFlags) - + " installStatus=" + ps.installStatus - + " enabled=" + ps.enabled); + pw.print(" timeStamp="); pw.println(ps.getTimeStampStr()); + pw.print(" signatures="); pw.println(ps.signatures); + pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed); + pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); + pw.print(" installStatus="); pw.print(ps.installStatus); + pw.print(" enabled="); pw.println(ps.enabled); if (ps.disabledComponents.size() > 0) { pw.println(" disabledComponents:"); for (String s : ps.disabledComponents) { - pw.println(" " + s); + pw.print(" "); pw.println(s); } } if (ps.enabledComponents.size() > 0) { pw.println(" enabledComponents:"); for (String s : ps.enabledComponents) { - pw.println(" " + s); + pw.print(" "); pw.println(s); } } - pw.println(" grantedPermissions:"); - for (String s : ps.grantedPermissions) { - pw.println(" " + s); + if (ps.grantedPermissions.size() > 0) { + pw.println(" grantedPermissions:"); + for (String s : ps.grantedPermissions) { + pw.print(" "); pw.println(s); + } } - pw.println(" loadedPermissions:"); - for (String s : ps.loadedPermissions) { - pw.println(" " + s); + if (ps.loadedPermissions.size() > 0) { + pw.println(" loadedPermissions:"); + for (String s : ps.loadedPermissions) { + pw.print(" "); pw.println(s); + } } } } @@ -4659,18 +4728,18 @@ class PackageManagerService extends IPackageManager.Stub { pw.println("Shared Users:"); { for (SharedUserSetting su : mSettings.mSharedUsers.values()) { - pw.println(" SharedUser [" + su.name + "] (" - + Integer.toHexString(System.identityHashCode(su)) - + "):"); - pw.println(" userId=" + su.userId - + " gids=" + arrayToString(su.gids)); + pw.print(" SharedUser ["); pw.print(su.name); pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(su))); + pw.println("):"); + pw.print(" userId="); pw.print(su.userId); + pw.print(" gids="); pw.println(arrayToString(su.gids)); pw.println(" grantedPermissions:"); for (String s : su.grantedPermissions) { - pw.println(" " + s); + pw.print(" "); pw.println(s); } pw.println(" loadedPermissions:"); for (String s : su.loadedPermissions) { - pw.println(" " + s); + pw.print(" "); pw.println(s); } } } @@ -5147,6 +5216,7 @@ class PackageManagerService extends IPackageManager.Stub { final String resourcePathString; private long timeStamp; private String timeStampString = "0"; + final int versionCode; PackageSignatures signatures = new PackageSignatures(); @@ -5158,17 +5228,29 @@ class PackageManagerService extends IPackageManager.Stub { HashSet enabledComponents = new HashSet(0); int enabled = COMPONENT_ENABLED_STATE_DEFAULT; int installStatus = PKG_INSTALL_COMPLETE; + + /* package name of the app that installed this package */ + String installerPackageName; PackageSettingBase(String name, File codePath, File resourcePath, - int pkgFlags) { + int pVersionCode, int pkgFlags) { super(pkgFlags); this.name = name; this.codePath = codePath; this.codePathString = codePath.toString(); this.resourcePath = resourcePath; this.resourcePathString = resourcePath.toString(); + this.versionCode = pVersionCode; } + public void setInstallerPackageName(String packageName) { + installerPackageName = packageName; + } + + String getInstallerPackageName() { + return installerPackageName; + } + public void setInstallStatus(int newStatus) { installStatus = newStatus; } @@ -5247,8 +5329,8 @@ class PackageManagerService extends IPackageManager.Stub { SharedUserSetting sharedUser; PackageSetting(String name, File codePath, File resourcePath, - int pkgFlags) { - super(name, codePath, resourcePath, pkgFlags); + int pVersionCode, int pkgFlags) { + super(name, codePath, resourcePath, pVersionCode, pkgFlags); } @Override @@ -5302,16 +5384,19 @@ class PackageManagerService extends IPackageManager.Stub { private final IntentResolver mPreferredActivities = new IntentResolver() { @Override - protected void dumpFilter(Printer out, String prefix, + protected void dumpFilter(PrintWriter out, String prefix, PreferredActivity filter) { - out.println(prefix - + Integer.toHexString(System.identityHashCode(filter)) - + " " + filter.mActivity.flattenToShortString() - + " match=0x" + Integer.toHexString(filter.mMatch)); + out.print(prefix); out.print( + Integer.toHexString(System.identityHashCode(filter))); + out.print(' '); + out.print(filter.mActivity.flattenToShortString()); + out.print(" match=0x"); + out.println( Integer.toHexString(filter.mMatch)); if (filter.mSetComponents != null) { - out.println(prefix + " Selected from:"); + out.print(prefix); out.println(" Selected from:"); for (int i=0; i 0) { packageSetting = addPackageLP(name.intern(), new File(codePathStr), - new File(resourcePathStr), userId, pkgFlags); + new File(resourcePathStr), userId, versionCode, pkgFlags); if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name + ": userId=" + userId + " pkg=" + packageSetting); if (packageSetting == null) { @@ -6272,7 +6398,7 @@ class PackageManagerService extends IPackageManager.Stub { ? Integer.parseInt(sharedIdStr) : 0; if (userId > 0) { packageSetting = new PendingPackage(name.intern(), new File(codePathStr), - new File(resourcePathStr), userId, pkgFlags); + new File(resourcePathStr), userId, versionCode, pkgFlags); packageSetting.setTimeStamp(timeStamp, timeStampStr); mPendingPackages.add((PendingPackage) packageSetting); if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name @@ -6297,6 +6423,7 @@ class PackageManagerService extends IPackageManager.Stub { + parser.getPositionDescription()); } if (packageSetting != null) { + packageSetting.installerPackageName = installerPackageName; final String enabledStr = parser.getAttributeValue(null, "enabled"); if (enabledStr != null) { if (enabledStr.equalsIgnoreCase("true")) { diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 9c6e9dcd68970c1763306f7f068536dc9339a81f..c5ea5fa9652c87b67a32eac79a32c4de848bec26 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -496,8 +496,10 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } public void acquireWakeLock(int flags, IBinder lock, String tag) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); int uid = Binder.getCallingUid(); + if (uid != Process.myUid()) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); + } long ident = Binder.clearCallingIdentity(); try { synchronized (mLocks) { @@ -554,14 +556,14 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage // by the current state so we never turn it more on than // it already is. if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) { - reactivateWakeLocksLocked(); + int oldWakeLockState = mWakeLockState; + mWakeLockState = mLocks.reactivateScreenLocksLocked(); if (mSpew) { Log.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState) - + " mLocks.gatherState()=0x" - + Integer.toHexString(mLocks.gatherState()) - + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)); + + " mWakeLockState=0x" + + Integer.toHexString(mWakeLockState) + + " previous wakeLockState=0x" + Integer.toHexString(oldWakeLockState)); } - mWakeLockState = mLocks.gatherState(); } else { if (mSpew) { Log.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState) @@ -598,7 +600,10 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } public void releaseWakeLock(IBinder lock) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); + int uid = Binder.getCallingUid(); + if (uid != Process.myUid()) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); + } synchronized (mLocks) { releaseWakeLockLocked(lock, false); @@ -653,17 +658,6 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } } - private void reactivateWakeLocksLocked() - { - int N = mLocks.size(); - for (int i=0; i mMulticasters = + new ArrayList(); + private int mMulticastEnabled; + private int mMulticastDisabled; + private final IBatteryStats mBatteryStats; /** @@ -165,7 +170,6 @@ public class WifiService extends IWifiManager.Stub { * Character buffer used to parse scan results (optimization) */ private static final int SCAN_RESULT_BUFFER_SIZE = 512; - private char[] mScanResultBuffer; private boolean mNeedReconfig; /* @@ -204,8 +208,6 @@ public class WifiService extends IWifiManager.Stub { } }; - mScanResultBuffer = new char [SCAN_RESULT_BUFFER_SIZE]; - HandlerThread wifiThread = new HandlerThread("WifiService"); wifiThread.start(); mWifiHandler = new WifiHandler(wifiThread.getLooper()); @@ -1217,61 +1219,13 @@ public class WifiService extends IWifiManager.Stub { lineBeg = lineEnd + 1; continue; } - int lineLen = lineEnd - lineBeg; - if (0 < lineLen && lineLen <= SCAN_RESULT_BUFFER_SIZE) { - int scanResultLevel = 0; - /* - * At most one thread should have access to the buffer at a time! - */ - synchronized(mScanResultBuffer) { - boolean parsingScanResultLevel = false; - for (int i = lineBeg; i < lineEnd; ++i) { - char ch = reply.charAt(i); - /* - * Assume that the signal level starts with a '-' - */ - if (ch == '-') { - /* - * Skip whatever instances of '-' we may have - * after we parse the signal level - */ - parsingScanResultLevel = (scanResultLevel == 0); - } else if (parsingScanResultLevel) { - int digit = Character.digit(ch, 10); - if (0 <= digit) { - scanResultLevel = - 10 * scanResultLevel + digit; - /* - * Replace the signal level number in - * the string with 0's for caching - */ - ch = '0'; - } else { - /* - * Reset the flag if we meet a non-digit - * character - */ - parsingScanResultLevel = false; - } - } - mScanResultBuffer[i - lineBeg] = ch; - } - if (scanResultLevel != 0) { - ScanResult scanResult = parseScanResult( - new String(mScanResultBuffer, 0, lineLen)); - if (scanResult != null) { - scanResult.level = -scanResultLevel; - scanList.add(scanResult); - } - } else if (DBG) { - Log.w(TAG, - "ScanResult.level=0: misformatted scan result?"); - } - } - } else if (0 < lineLen) { - if (DBG) { - Log.w(TAG, "Scan result line is too long: " + - (lineEnd - lineBeg) + ", skipping the line!"); + if (lineEnd > lineBeg) { + String line = reply.substring(lineBeg, lineEnd); + ScanResult scanResult = parseScanResult(line); + if (scanResult != null) { + scanList.add(scanResult); + } else if (DBG) { + Log.w(TAG, "misformatted scan result for: " + line); } } lineBeg = lineEnd + 1; @@ -1294,21 +1248,29 @@ public class WifiService extends IWifiManager.Stub { * must synchronized here! */ synchronized (mScanResultCache) { - scanResult = mScanResultCache.get(line); - if (scanResult == null) { - String[] result = scanResultPattern.split(line); - if (3 <= result.length && result.length <= 5) { - // bssid | frequency | level | flags | ssid - int frequency; - int level; - try { - frequency = Integer.parseInt(result[1]); - level = Integer.parseInt(result[2]); - } catch (NumberFormatException e) { - frequency = 0; - level = 0; - } + String[] result = scanResultPattern.split(line); + if (3 <= result.length && result.length <= 5) { + String bssid = result[0]; + // bssid | frequency | level | flags | ssid + int frequency; + int level; + try { + frequency = Integer.parseInt(result[1]); + level = Integer.parseInt(result[2]); + /* some implementations avoid negative values by adding 256 + * so we need to adjust for that here. + */ + if (level > 0) level -= 256; + } catch (NumberFormatException e) { + frequency = 0; + level = 0; + } + // bssid is the hash key + scanResult = mScanResultCache.get(bssid); + if (scanResult != null) { + scanResult.level = level; + } else { /* * The formatting of the results returned by * wpa_supplicant is intended to make the fields @@ -1341,13 +1303,13 @@ public class WifiService extends IWifiManager.Stub { if (0 < ssid.trim().length()) { scanResult = new ScanResult( - ssid, result[0], flags, level, frequency); - mScanResultCache.put(line, scanResult); + ssid, bssid, flags, level, frequency); + mScanResultCache.put(bssid, scanResult); } - } else { - Log.w(TAG, "Misformatted scan result text with " + - result.length + " fields: " + line); } + } else { + Log.w(TAG, "Misformatted scan result text with " + + result.length + " fields: " + line); } } } @@ -1770,21 +1732,9 @@ public class WifiService extends IWifiManager.Stub { } } - private class WifiLock implements IBinder.DeathRecipient { - String mTag; - int mLockMode; - IBinder mBinder; - + private class WifiLock extends WifiDeathRecipient { WifiLock(int lockMode, String tag, IBinder binder) { - super(); - mTag = tag; - mLockMode = lockMode; - mBinder = binder; - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } + super(lockMode, tag, binder); } public void binderDied() { @@ -1794,7 +1744,7 @@ public class WifiService extends IWifiManager.Stub { } public String toString() { - return "WifiLock{" + mTag + " type=" + mLockMode + " binder=" + mBinder + "}"; + return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}"; } } @@ -1814,7 +1764,7 @@ public class WifiService extends IWifiManager.Stub { return WifiManager.WIFI_MODE_FULL; } for (WifiLock l : mList) { - if (l.mLockMode == WifiManager.WIFI_MODE_FULL) { + if (l.mMode == WifiManager.WIFI_MODE_FULL) { return WifiManager.WIFI_MODE_FULL; } } @@ -1869,7 +1819,7 @@ public class WifiService extends IWifiManager.Stub { int uid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); try { - switch(wifiLock.mLockMode) { + switch(wifiLock.mMode) { case WifiManager.WIFI_MODE_FULL: ++mFullLocksAcquired; mBatteryStats.noteFullWifiLockAcquired(uid); @@ -1905,7 +1855,7 @@ public class WifiService extends IWifiManager.Stub { int uid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); try { - switch(wifiLock.mLockMode) { + switch(wifiLock.mMode) { case WifiManager.WIFI_MODE_FULL: ++mFullLocksReleased; mBatteryStats.noteFullWifiLockReleased(uid); @@ -1924,4 +1874,110 @@ public class WifiService extends IWifiManager.Stub { updateWifiState(); return hadLock; } + + private abstract class WifiDeathRecipient + implements IBinder.DeathRecipient { + String mTag; + int mMode; + IBinder mBinder; + + WifiDeathRecipient(int mode, String tag, IBinder binder) { + super(); + mTag = tag; + mMode = mode; + mBinder = binder; + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + } + + private class WifiMulticaster extends WifiDeathRecipient { + WifiMulticaster(String tag, IBinder binder) { + super(Binder.getCallingUid(), tag, binder); + } + + public void binderDied() { + Log.e(TAG, "WifiMulticaster binderDied"); + synchronized (mMulticasters) { + int i = mMulticasters.indexOf(this); + if (i != -1) { + removeMulticasterLocked(i, mMode); + } + } + } + + public String toString() { + return "WifiMulticaster{" + mTag + " binder=" + mBinder + "}"; + } + + public int getUid() { + return mMode; + } + } + + public void enableWifiMulticast(IBinder binder, String tag) { + enforceChangePermission(); + + synchronized (mMulticasters) { + mMulticastEnabled++; + mMulticasters.add(new WifiMulticaster(tag, binder)); + // Note that we could call stopPacketFiltering only when + // our new size == 1 (first call), but this function won't + // be called often and by making the stopPacket call each + // time we're less fragile and self-healing. + WifiNative.stopPacketFiltering(); + } + + int uid = Binder.getCallingUid(); + Long ident = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteWifiMulticastEnabled(uid); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + public void disableWifiMulticast() { + enforceChangePermission(); + + int uid = Binder.getCallingUid(); + synchronized (mMulticasters) { + mMulticastDisabled++; + int size = mMulticasters.size(); + for (int i = size - 1; i >= 0; i--) { + WifiMulticaster m = mMulticasters.get(i); + if ((m != null) && (m.getUid() == uid)) { + removeMulticasterLocked(i, uid); + } + } + } + } + + private void removeMulticasterLocked(int i, int uid) + { + mMulticasters.remove(i); + if (mMulticasters.size() == 0) { + WifiNative.startPacketFiltering(); + } + + Long ident = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteWifiMulticastDisabled(uid); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + public boolean isWifiMulticastEnabled() { + enforceAccessPermission(); + + synchronized (mMulticasters) { + return (mMulticasters.size() > 0); + } + } } diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java index fe97b93273055078a0f6cebc29102dd5c04b206f..9443a958199a71e7814f2d58ea1963115e56508c 100644 --- a/services/java/com/android/server/WifiWatchdogService.java +++ b/services/java/com/android/server/WifiWatchdogService.java @@ -75,14 +75,6 @@ public class WifiWatchdogService { private static final boolean V = false || Config.LOGV; private static final boolean D = true || Config.LOGD; - /* - * When this was "net.dns1", sometimes the mobile data's DNS was seen - * instead due to a race condition. All we really care about is the - * DHCP-replied DNS server anyway. - */ - /** The system property whose value provides the current DNS address. */ - private static final String SYSTEMPROPERTY_KEY_DNS = "dhcp.tiwlan0.dns1"; - private Context mContext; private ContentResolver mContentResolver; private WifiStateTracker mWifiStateTracker; diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 0b1ddc846be5d91ef398596a46f4e8c46990c45e..3fa5bafc01011b65434a45e22342ab6ff67b76da 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -77,7 +77,6 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.TokenWatcher; import android.provider.Settings; -import android.util.Config; import android.util.EventLog; import android.util.Log; import android.util.SparseIntArray; @@ -137,7 +136,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo static final boolean PROFILE_ORIENTATION = false; static final boolean BLUR = true; - static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean localLOGV = DEBUG; static final int LOG_WM_NO_SURFACE_MEMORY = 31000; @@ -180,6 +179,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo static final int UPDATE_FOCUS_PLACING_SURFACES = 2; static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3; + /** The minimum time between dispatching touch events. */ + int mMinWaitTimeBetweenTouchEvents = 1000 / 35; + + // Last touch event time + long mLastTouchEventTime = 0; + + // Last touch event type + int mLastTouchEventType = OTHER_EVENT; + + // Time to wait before calling useractivity again. This saves CPU usage + // when we get a flood of touch events. + static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000; + + // Last time we call user activity + long mLastUserActivityCallTime = 0; + + // Last time we updated battery stats + long mLastBatteryStatsCallTime = 0; + private static final String SYSTEM_SECURE = "ro.secure"; /** @@ -2023,7 +2041,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo wtoken.appFullscreen = fullscreen; wtoken.requestedOrientation = requestedOrientation; mAppTokens.add(addPos, wtoken); - if (Config.LOGV) Log.v(TAG, "Adding new app token: " + wtoken); + if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken); mTokenMap.put(token.asBinder(), wtoken); mTokenList.add(wtoken); @@ -2079,13 +2097,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo int pos = mAppTokens.size() - 1; int curGroup = 0; int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + boolean findingBehind = false; boolean haveGroup = false; boolean lastFullscreen = false; while (pos >= 0) { AppWindowToken wtoken = mAppTokens.get(pos); pos--; - // if we're about to tear down this window, don't use it for orientation - if (!wtoken.hidden && wtoken.hiddenRequested) { + // if we're about to tear down this window and not seek for + // the behind activity, don't use it for orientation + if (!findingBehind + && (!wtoken.hidden && wtoken.hiddenRequested)) { continue; } @@ -2109,10 +2130,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } int or = wtoken.requestedOrientation; - // If this application is fullscreen, then just take whatever + // If this application is fullscreen, and didn't explicitly say + // to use the orientation behind it, then just take whatever // orientation it has and ignores whatever is under it. lastFullscreen = wtoken.appFullscreen; - if (lastFullscreen) { + if (lastFullscreen + && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { return or; } // If this application has requested an explicit orientation, @@ -2124,6 +2147,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo or == ActivityInfo.SCREEN_ORIENTATION_USER) { return or; } + findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); } return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } @@ -3689,9 +3713,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // ------------------------------------------------------------- private final void wakeupIfNeeded(WindowState targetWin, int eventType) { - if (targetWin == null || - targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) { - mPowerManager.userActivity(SystemClock.uptimeMillis(), false, eventType); + long curTime = SystemClock.uptimeMillis(); + + if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) { + if (mLastTouchEventType == eventType && + (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) { + return; + } + mLastUserActivityCallTime = curTime; + mLastTouchEventType = eventType; + } + + if (targetWin == null + || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) { + mPowerManager.userActivity(curTime, false, eventType, false); } } @@ -3759,7 +3794,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // events in such a way, since this means the user is moving the // pointer without actually pressing down. All other cases should // be atypical, so let's log them. - if (ev.getAction() != MotionEvent.ACTION_MOVE) { + if (action != MotionEvent.ACTION_MOVE) { Log.w(TAG, "No window to dispatch pointer action " + ev.getAction()); } if (qev != null) { @@ -3846,7 +3881,39 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo return false; } } //end if target - + + // TODO remove once we settle on a value or make it app specific + if (action == MotionEvent.ACTION_DOWN) { + int max_events_per_sec = 35; + try { + max_events_per_sec = Integer.parseInt(SystemProperties + .get("windowsmgr.max_events_per_sec")); + if (max_events_per_sec < 1) { + max_events_per_sec = 35; + } + } catch (NumberFormatException e) { + } + mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec; + } + + /* + * Throttle events to minimize CPU usage when there's a flood of events + * e.g. constant contact with the screen + */ + if (action == MotionEvent.ACTION_MOVE) { + long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents; + long now = SystemClock.uptimeMillis(); + if (now < nextEventTime) { + try { + Thread.sleep(nextEventTime - now); + } catch (InterruptedException e) { + } + mLastTouchEventTime = nextEventTime; + } else { + mLastTouchEventTime = now; + } + } + synchronized(mWindowMap) { if (qev != null && action == MotionEvent.ACTION_MOVE) { mKeyWaiter.bindTargetWindowLocked(target, @@ -4801,14 +4868,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo mPaused = true; } else { if (mLastWin == null) { - if (Config.LOGI) Log.i( - TAG, "Key dispatching not paused: no last window."); + Log.i(TAG, "Key dispatching not paused: no last window."); } else if (mFinished) { - if (Config.LOGI) Log.i( - TAG, "Key dispatching not paused: finished last key."); + Log.i(TAG, "Key dispatching not paused: finished last key."); } else { - if (Config.LOGI) Log.i( - TAG, "Key dispatching not paused: window in higher layer."); + Log.i(TAG, "Key dispatching not paused: window in higher layer."); } } */ @@ -4926,7 +4990,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) { mPowerManager.userActivity(event.when, false, - LocalPowerManager.BUTTON_EVENT); + LocalPowerManager.BUTTON_EVENT, false); } if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) { @@ -5086,11 +5150,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo eventType = LocalPowerManager.OTHER_EVENT; } try { - mBatteryStats.noteInputEvent(); + long now = SystemClock.uptimeMillis(); + + if ((now - mLastBatteryStatsCallTime) + >= MIN_TIME_BETWEEN_USERACTIVITIES) { + mLastBatteryStatsCallTime = now; + mBatteryStats.noteInputEvent(); + } } catch (RemoteException e) { // Ignore } - mPowerManager.userActivity(curTime, false, eventType); + mPowerManager.userActivity(curTime, false, eventType, false); switch (ev.classType) { case RawInputEvent.CLASS_KEYBOARD: KeyEvent ke = (KeyEvent)ev.event; @@ -5179,6 +5249,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo final IInputContext mInputContext; final int mUid; final int mPid; + final String mStringName; SurfaceSession mSurfaceSession; int mNumWindow = 0; boolean mClientDead = false; @@ -5202,6 +5273,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo mInputContext = inputContext; mUid = Binder.getCallingUid(); mPid = Binder.getCallingPid(); + StringBuilder sb = new StringBuilder(); + sb.append("Session{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" uid "); + sb.append(mUid); + sb.append("}"); + mStringName = sb.toString(); + synchronized (mWindowMap) { if (mInputMethodManager == null && mHaveInputMethods) { IBinder b = ServiceManager.getService( @@ -5381,20 +5460,24 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "mNumWindow=" + mNumWindow - + " mClientDead=" + mClientDead - + " mSurfaceSession=" + mSurfaceSession); - pw.println(prefix + "mPendingPointerWindow=" + mPendingPointerWindow - + " mPendingPointerMove=" + mPendingPointerMove); - pw.println(prefix + "mPendingTrackballWindow=" + mPendingTrackballWindow - + " mPendingTrackballMove=" + mPendingTrackballMove); + pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow); + pw.print(" mClientDead="); pw.print(mClientDead); + pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); + if (mPendingPointerWindow != null || mPendingPointerMove != null) { + pw.print(prefix); + pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow); + pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove); + } + if (mPendingTrackballWindow != null || mPendingTrackballMove != null) { + pw.print(prefix); + pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow); + pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove); + } } @Override public String toString() { - return "Session{" - + Integer.toHexString(System.identityHashCode(this)) + "}"; + return mStringName; } } @@ -6462,67 +6545,114 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "mSession=" + mSession - + " mClient=" + mClient.asBinder()); - pw.println(prefix + "mAttrs=" + mAttrs); - pw.println(prefix + "mAttachedWindow=" + mAttachedWindow - + " mLayoutAttached=" + mLayoutAttached - + " mIsImWindow=" + mIsImWindow); - pw.println(prefix + "mBaseLayer=" + mBaseLayer - + " mSubLayer=" + mSubLayer - + " mAnimLayer=" + mLayer + "+" - + (mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment - : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)) - + "=" + mAnimLayer - + " mLastLayer=" + mLastLayer); - pw.println(prefix + "mSurface=" + mSurface); - pw.println(prefix + "mToken=" + mToken); - pw.println(prefix + "mRootToken=" + mRootToken); - pw.println(prefix + "mAppToken=" + mAppToken); - pw.println(prefix + "mTargetAppToken=" + mTargetAppToken); - pw.println(prefix + "mViewVisibility=0x" + Integer.toHexString(mViewVisibility) - + " mPolicyVisibility=" + mPolicyVisibility - + " (after=" + mPolicyVisibilityAfterAnim - + ") mAttachedHidden=" + mAttachedHidden - + " mLastHidden=" + mLastHidden - + " mHaveFrame=" + mHaveFrame); - pw.println(prefix + "Requested w=" + mRequestedWidth + " h=" + mRequestedHeight - + " x=" + mReqXPos + " y=" + mReqYPos); - pw.println(prefix + "mGivenContentInsets=" + mGivenContentInsets.toShortString() - + " mGivenVisibleInsets=" + mGivenVisibleInsets.toShortString() - + " mTouchableInsets=" + mTouchableInsets - + " pending=" + mGivenInsetsPending); - pw.println(prefix + "mShownFrame=" + mShownFrame.toShortString() - + " last=" + mLastShownFrame.toShortString()); - pw.println(prefix + "mFrame=" + mFrame.toShortString() - + " last=" + mLastFrame.toShortString()); - pw.println(prefix + "mContainingFrame=" + mContainingFrame.toShortString() - + " mDisplayFrame=" + mDisplayFrame.toShortString()); - pw.println(prefix + "mContentFrame=" + mContentFrame.toShortString() - + " mVisibleFrame=" + mVisibleFrame.toShortString()); - pw.println(prefix + "mContentInsets=" + mContentInsets.toShortString() - + " last=" + mLastContentInsets.toShortString() - + " mVisibleInsets=" + mVisibleInsets.toShortString() - + " last=" + mLastVisibleInsets.toShortString()); - pw.println(prefix + "mShownAlpha=" + mShownAlpha - + " mAlpha=" + mAlpha + " mLastAlpha=" + mLastAlpha); - pw.println(prefix + "mAnimating=" + mAnimating - + " mLocalAnimating=" + mLocalAnimating - + " mAnimationIsEntrance=" + mAnimationIsEntrance - + " mAnimation=" + mAnimation); - pw.println(prefix + "XForm: has=" + mHasTransformation - + " " + mTransformation.toShortString()); - pw.println(prefix + "mDrawPending=" + mDrawPending - + " mCommitDrawPending=" + mCommitDrawPending - + " mReadyToShow=" + mReadyToShow - + " mHasDrawn=" + mHasDrawn); - pw.println(prefix + "mExiting=" + mExiting - + " mRemoveOnExit=" + mRemoveOnExit - + " mDestroying=" + mDestroying - + " mRemoved=" + mRemoved); - pw.println(prefix + "mOrientationChanging=" + mOrientationChanging - + " mAppFreezing=" + mAppFreezing); + StringBuilder sb = new StringBuilder(64); + + pw.print(prefix); pw.print("mSession="); pw.print(mSession); + pw.print(" mClient="); pw.println(mClient.asBinder()); + pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs); + if (mAttachedWindow != null || mLayoutAttached) { + pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow); + pw.print(" mLayoutAttached="); pw.println(mLayoutAttached); + } + if (mIsImWindow) { + pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow); + } + pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer); + pw.print(" mSubLayer="); pw.print(mSubLayer); + pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+"); + pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment + : (mAppToken != null ? mAppToken.animLayerAdjustment : 0))); + pw.print("="); pw.print(mAnimLayer); + pw.print(" mLastLayer="); pw.println(mLastLayer); + if (mSurface != null) { + pw.print(prefix); pw.print("mSurface="); pw.println(mSurface); + } + pw.print(prefix); pw.print("mToken="); pw.println(mToken); + pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken); + if (mAppToken != null) { + pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken); + } + if (mTargetAppToken != null) { + pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken); + } + pw.print(prefix); pw.print("mViewVisibility=0x"); + pw.print(Integer.toHexString(mViewVisibility)); + pw.print(" mLastHidden="); pw.print(mLastHidden); + pw.print(" mHaveFrame="); pw.println(mHaveFrame); + if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) { + pw.print(prefix); pw.print("mPolicyVisibility="); + pw.print(mPolicyVisibility); + pw.print(" mPolicyVisibilityAfterAnim="); + pw.print(mPolicyVisibilityAfterAnim); + pw.print(" mAttachedHidden="); pw.println(mAttachedHidden); + } + pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth); + pw.print(" h="); pw.print(mRequestedHeight); + pw.print(" x="); pw.print(mReqXPos); + pw.print(" y="); pw.println(mReqYPos); + pw.print(prefix); pw.print("mGivenContentInsets="); + mGivenContentInsets.printShortString(pw); + pw.print(" mGivenVisibleInsets="); + mGivenVisibleInsets.printShortString(pw); + pw.println(); + if (mTouchableInsets != 0 || mGivenInsetsPending) { + pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets); + pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending); + } + pw.print(prefix); pw.print("mShownFrame="); + mShownFrame.printShortString(pw); + pw.print(" last="); mLastShownFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw); + pw.print(" last="); mLastFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mContainingFrame="); + mContainingFrame.printShortString(pw); + pw.print(" mDisplayFrame="); + mDisplayFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mContentFrame="); mContentFrame.printShortString(pw); + pw.print(" mVisibleFrame="); mVisibleFrame.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("mContentInsets="); mContentInsets.printShortString(pw); + pw.print(" last="); mLastContentInsets.printShortString(pw); + pw.print(" mVisibleInsets="); mVisibleInsets.printShortString(pw); + pw.print(" last="); mLastVisibleInsets.printShortString(pw); + pw.println(); + if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) { + pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha); + pw.print(" mAlpha="); pw.print(mAlpha); + pw.print(" mLastAlpha="); pw.println(mLastAlpha); + } + if (mAnimating || mLocalAnimating || mAnimationIsEntrance + || mAnimation != null) { + pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating); + pw.print(" mLocalAnimating="); pw.print(mLocalAnimating); + pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance); + pw.print(" mAnimation="); pw.println(mAnimation); + } + if (mHasTransformation || mHasLocalTransformation) { + pw.print(prefix); pw.print("XForm: has="); + pw.print(mHasTransformation); + pw.print(" hasLocal="); pw.print(mHasLocalTransformation); + pw.print(" "); mTransformation.printShortString(pw); + pw.println(); + } + pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending); + pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending); + pw.print(" mReadyToShow="); pw.print(mReadyToShow); + pw.print(" mHasDrawn="); pw.println(mHasDrawn); + if (mExiting || mRemoveOnExit || mDestroying || mRemoved) { + pw.print(prefix); pw.print("mExiting="); pw.print(mExiting); + pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit); + pw.print(" mDestroying="); pw.print(mDestroying); + pw.print(" mRemoved="); pw.println(mRemoved); + } + if (mOrientationChanging || mAppFreezing) { + pw.print(prefix); pw.print("mOrientationChanging="); + pw.print(mOrientationChanging); + pw.print(" mAppFreezing="); pw.println(mAppFreezing); + } } @Override @@ -6548,6 +6678,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // not be removed when all windows are removed. final boolean explicit; + // For printing. + String stringName; + // If this is an AppWindowToken, this is non-null. AppWindowToken appWindowToken; @@ -6570,18 +6703,23 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "token=" + token); - pw.println(prefix + "windows=" + windows); - pw.println(prefix + "windowType=" + windowType + " hidden=" + hidden - + " hasVisible=" + hasVisible); + pw.print(prefix); pw.print("token="); pw.println(token); + pw.print(prefix); pw.print("windows="); pw.println(windows); + pw.print(prefix); pw.print("windowType="); pw.print(windowType); + pw.print(" hidden="); pw.print(hidden); + pw.print(" hasVisible="); pw.println(hasVisible); } @Override public String toString() { - return "WindowToken{" - + Integer.toHexString(System.identityHashCode(this)) - + " token=" + token + "}"; + if (stringName == null) { + StringBuilder sb = new StringBuilder(); + sb.append("WindowToken{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" token="); sb.append(token); sb.append('}'); + stringName = sb.toString(); + } + return stringName; } }; @@ -6869,38 +7007,66 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo void dump(PrintWriter pw, String prefix) { super.dump(pw, prefix); - pw.println(prefix + "app=" + (appToken != null)); - pw.println(prefix + "allAppWindows=" + allAppWindows); - pw.println(prefix + "groupId=" + groupId - + " requestedOrientation=" + requestedOrientation); - pw.println(prefix + "hiddenRequested=" + hiddenRequested - + " clientHidden=" + clientHidden - + " willBeHidden=" + willBeHidden - + " reportedVisible=" + reportedVisible); - pw.println(prefix + "paused=" + paused - + " freezingScreen=" + freezingScreen); - pw.println(prefix + "numInterestingWindows=" + numInterestingWindows - + " numDrawnWindows=" + numDrawnWindows - + " inPendingTransaction=" + inPendingTransaction - + " allDrawn=" + allDrawn); - pw.println(prefix + "animating=" + animating - + " animation=" + animation); - pw.println(prefix + "animLayerAdjustment=" + animLayerAdjustment - + " transformation=" + transformation.toShortString()); - pw.println(prefix + "startingData=" + startingData - + " removed=" + removed - + " firstWindowDrawn=" + firstWindowDrawn); - pw.println(prefix + "startingWindow=" + startingWindow - + " startingView=" + startingView - + " startingDisplayed=" + startingDisplayed - + " startingMoved" + startingMoved); + if (appToken != null) { + pw.print(prefix); pw.println("app=true"); + } + if (allAppWindows.size() > 0) { + pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows); + } + pw.print(prefix); pw.print("groupId="); pw.print(groupId); + pw.print(" requestedOrientation="); pw.println(requestedOrientation); + pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested); + pw.print(" clientHidden="); pw.print(clientHidden); + pw.print(" willBeHidden="); pw.print(willBeHidden); + pw.print(" reportedVisible="); pw.println(reportedVisible); + if (paused || freezingScreen) { + pw.print(prefix); pw.print("paused="); pw.print(paused); + pw.print(" freezingScreen="); pw.println(freezingScreen); + } + if (numInterestingWindows != 0 || numDrawnWindows != 0 + || inPendingTransaction || allDrawn) { + pw.print(prefix); pw.print("numInterestingWindows="); + pw.print(numInterestingWindows); + pw.print(" numDrawnWindows="); pw.print(numDrawnWindows); + pw.print(" inPendingTransaction="); pw.print(inPendingTransaction); + pw.print(" allDrawn="); pw.println(allDrawn); + } + if (animating || animation != null) { + pw.print(prefix); pw.print("animating="); pw.print(animating); + pw.print(" animation="); pw.println(animation); + } + if (animLayerAdjustment != 0) { + pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment); + } + if (hasTransformation) { + pw.print(prefix); pw.print("hasTransformation="); pw.print(hasTransformation); + pw.print(" transformation="); transformation.printShortString(pw); + pw.println(); + } + if (startingData != null || removed || firstWindowDrawn) { + pw.print(prefix); pw.print("startingData="); pw.print(startingData); + pw.print(" removed="); pw.print(removed); + pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn); + } + if (startingWindow != null || startingView != null + || startingDisplayed || startingMoved) { + pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); + pw.print(" startingView="); pw.print(startingView); + pw.print(" startingDisplayed="); pw.print(startingDisplayed); + pw.print(" startingMoved"); pw.println(startingMoved); + } } @Override public String toString() { - return "AppWindowToken{" - + Integer.toHexString(System.identityHashCode(this)) - + " token=" + token + "}"; + if (stringName == null) { + StringBuilder sb = new StringBuilder(); + sb.append("AppWindowToken{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" token="); sb.append(token); sb.append('}'); + stringName = sb.toString(); + } + return stringName; } } @@ -7423,7 +7589,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo private boolean mInLayout = false; private final void performLayoutAndPlaceSurfacesLocked() { if (mInLayout) { - if (Config.DEBUG) { + if (DEBUG) { throw new RuntimeException("Recursive call!"); } Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout"); @@ -8656,7 +8822,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println("Current Window Manager state:"); for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = (WindowState)mWindows.get(i); - pw.println(" Window #" + i + ":"); + pw.print(" Window #"); pw.print(i); pw.print(' '); + pw.print(w); pw.println(":"); w.dump(pw, " "); } if (mInputMethodDialogs.size() > 0) { @@ -8664,7 +8831,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Input method dialogs:"); for (int i=mInputMethodDialogs.size()-1; i>=0; i--) { WindowState w = mInputMethodDialogs.get(i); - pw.println(" IM Dialog #" + i + ": " + w); + pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w); } } if (mPendingRemove.size() > 0) { @@ -8672,7 +8839,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Remove pending for:"); for (int i=mPendingRemove.size()-1; i>=0; i--) { WindowState w = mPendingRemove.get(i); - pw.println(" Remove #" + i + ":"); + pw.print(" Remove #"); pw.print(i); pw.print(' '); + pw.print(w); pw.println(":"); w.dump(pw, " "); } } @@ -8681,7 +8849,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Windows force removing:"); for (int i=mForceRemoves.size()-1; i>=0; i--) { WindowState w = mForceRemoves.get(i); - pw.println(" Removing #" + i + ":"); + pw.print(" Removing #"); pw.print(i); pw.print(' '); + pw.print(w); pw.println(":"); w.dump(pw, " "); } } @@ -8690,7 +8859,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Windows waiting to destroy their surface:"); for (int i=mDestroySurface.size()-1; i>=0; i--) { WindowState w = mDestroySurface.get(i); - pw.println(" Destroy #" + i + ":"); + pw.print(" Destroy #"); pw.print(i); pw.print(' '); + pw.print(w); pw.println(":"); w.dump(pw, " "); } } @@ -8699,7 +8869,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Windows losing focus:"); for (int i=mLosingFocus.size()-1; i>=0; i--) { WindowState w = mLosingFocus.get(i); - pw.println(" Losing #" + i + ":"); + pw.print(" Losing #"); pw.print(i); pw.print(' '); + pw.print(w); pw.println(":"); w.dump(pw, " "); } } @@ -8709,7 +8880,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo Iterator it = mSessions.iterator(); while (it.hasNext()) { Session s = it.next(); - pw.println(" Session " + s); + pw.print(" Session "); pw.print(s); pw.println(':'); s.dump(pw, " "); } } @@ -8719,7 +8890,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo Iterator it = mTokenMap.values().iterator(); while (it.hasNext()) { WindowToken token = it.next(); - pw.println(" Token " + token.token); + pw.print(" Token "); pw.print(token.token); pw.println(':'); token.dump(pw, " "); } } @@ -8727,14 +8898,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" "); pw.println(" Window token list:"); for (int i=0; i 0) { pw.println(" "); pw.println(" Application tokens in Z order:"); for (int i=mAppTokens.size()-1; i>=0; i--) { - pw.println(" AppWindowToken #" + i + ": " + mAppTokens.get(i)); + pw.print(" App #"); pw.print(i); pw.print(": "); + pw.println(mAppTokens.get(i)); } } if (mFinishedStarting.size() > 0) { @@ -8742,7 +8915,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Finishing start of application tokens:"); for (int i=mFinishedStarting.size()-1; i>=0; i--) { WindowToken token = mFinishedStarting.get(i); - pw.println(" Finish Starting App Token #" + i + ":"); + pw.print(" Finished Starting #"); pw.print(i); + pw.print(' '); pw.print(token); pw.println(':'); token.dump(pw, " "); } } @@ -8751,7 +8925,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Exiting tokens:"); for (int i=mExitingTokens.size()-1; i>=0; i--) { WindowToken token = mExitingTokens.get(i); - pw.println(" Exiting Token #" + i + ":"); + pw.print(" Exiting #"); pw.print(i); + pw.print(' '); pw.print(token); pw.println(':'); token.dump(pw, " "); } } @@ -8760,54 +8935,59 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" Exiting application tokens:"); for (int i=mExitingAppTokens.size()-1; i>=0; i--) { WindowToken token = mExitingAppTokens.get(i); - pw.println(" Exiting App Token #" + i + ":"); + pw.print(" Exiting App #"); pw.print(i); + pw.print(' '); pw.print(token); pw.println(':'); token.dump(pw, " "); } } pw.println(" "); - pw.println(" mCurrentFocus=" + mCurrentFocus); - pw.println(" mLastFocus=" + mLastFocus); - pw.println(" mFocusedApp=" + mFocusedApp); - pw.println(" mInputMethodTarget=" + mInputMethodTarget); - pw.println(" mInputMethodWindow=" + mInputMethodWindow); - pw.println(" mInTouchMode=" + mInTouchMode); - pw.println(" mSystemBooted=" + mSystemBooted - + " mDisplayEnabled=" + mDisplayEnabled); - pw.println(" mLayoutNeeded=" + mLayoutNeeded - + " mBlurShown=" + mBlurShown); - pw.println(" mDimShown=" + mDimShown - + " current=" + mDimCurrentAlpha - + " target=" + mDimTargetAlpha - + " delta=" + mDimDeltaPerMs - + " lastAnimTime=" + mLastDimAnimTime); - pw.println(" mInputMethodAnimLayerAdjustment=" - + mInputMethodAnimLayerAdjustment); - pw.println(" mDisplayFrozen=" + mDisplayFrozen - + " mWindowsFreezingScreen=" + mWindowsFreezingScreen - + " mAppsFreezingScreen=" + mAppsFreezingScreen); - pw.println(" mRotation=" + mRotation - + ", mForcedAppOrientation=" + mForcedAppOrientation - + ", mRequestedRotation=" + mRequestedRotation); - pw.println(" mAnimationPending=" + mAnimationPending - + " mWindowAnimationScale=" + mWindowAnimationScale - + " mTransitionWindowAnimationScale=" + mTransitionAnimationScale); - pw.println(" mNextAppTransition=0x" - + Integer.toHexString(mNextAppTransition) - + ", mAppTransitionReady=" + mAppTransitionReady - + ", mAppTransitionTimeout=" + mAppTransitionTimeout); - pw.println(" mStartingIconInTransition=" + mStartingIconInTransition - + ", mSkipAppTransitionAnimation=" + mSkipAppTransitionAnimation); - pw.println(" mOpeningApps=" + mOpeningApps); - pw.println(" mClosingApps=" + mClosingApps); - pw.println(" DisplayWidth=" + mDisplay.getWidth() - + " DisplayHeight=" + mDisplay.getHeight()); + pw.print(" mCurrentFocus="); pw.println(mCurrentFocus); + pw.print(" mLastFocus="); pw.println(mLastFocus); + pw.print(" mFocusedApp="); pw.println(mFocusedApp); + pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget); + pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow); + pw.print(" mInTouchMode="); pw.println(mInTouchMode); + pw.print(" mSystemBooted="); pw.print(mSystemBooted); + pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); + pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded); + pw.print(" mBlurShown="); pw.println(mBlurShown); + pw.print(" mDimShown="); pw.print(mDimShown); + pw.print(" current="); pw.print(mDimCurrentAlpha); + pw.print(" target="); pw.print(mDimTargetAlpha); + pw.print(" delta="); pw.print(mDimDeltaPerMs); + pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime); + pw.print(" mInputMethodAnimLayerAdjustment="); + pw.println(mInputMethodAnimLayerAdjustment); + pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen); + pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen); + pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen); + pw.print(" mRotation="); pw.print(mRotation); + pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation); + pw.print(", mRequestedRotation="); pw.println(mRequestedRotation); + pw.print(" mAnimationPending="); pw.print(mAnimationPending); + pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale); + pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale); + pw.print(" mNextAppTransition=0x"); + pw.print(Integer.toHexString(mNextAppTransition)); + pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady); + pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout); + pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); + pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); + if (mOpeningApps.size() > 0) { + pw.print(" mOpeningApps="); pw.println(mOpeningApps); + } + if (mClosingApps.size() > 0) { + pw.print(" mClosingApps="); pw.println(mClosingApps); + } + pw.print(" DisplayWidth="); pw.print(mDisplay.getWidth()); + pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight()); pw.println(" KeyWaiter state:"); - pw.println(" mLastWin=" + mKeyWaiter.mLastWin - + " mLastBinder=" + mKeyWaiter.mLastBinder); - pw.println(" mFinished=" + mKeyWaiter.mFinished - + " mGotFirstWindow=" + mKeyWaiter.mGotFirstWindow - + " mEventDispatching=" + mKeyWaiter.mEventDispatching - + " mTimeToSwitch=" + mKeyWaiter.mTimeToSwitch); + pw.print(" mLastWin="); pw.print(mKeyWaiter.mLastWin); + pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder); + pw.print(" mFinished="); pw.print(mKeyWaiter.mFinished); + pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow); + pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching); + pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch); } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d676c00b952e500c204db7fb21f130211b15390e..9471eff95f3f5ab67dc6a3e648c607ccdc536340 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -169,6 +169,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen static final int LOG_BOOT_PROGRESS_AMS_READY = 3040; static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050; + // The flags that are set for all calls we make to the package manager. + static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES + | PackageManager.GET_SUPPORTS_DENSITIES; + private static final String SYSTEM_SECURE = "ro.secure"; // This is the maximum number of application processes we would like @@ -681,6 +685,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen */ HashMap mAppBindArgs; + /** + * Temporary to avoid allocations. Protected by main lock. + */ + final StringBuilder mStringBuilder = new StringBuilder(256); + /** * Used to control how we initialize the service. */ @@ -701,6 +710,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen */ boolean mSleeping = false; + /** + * Set if we are shutting down the system, similar to sleeping. + */ + boolean mShuttingDown = false; + /** * Set when the system is going to sleep, until we have * successfully paused the current activity and released our wake lock. @@ -778,6 +792,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen long mLastCpuTime = 0; long mLastWriteTime = 0; + long mInitialStartTime = 0; + /** * Set to true after the system has finished booting. */ @@ -861,7 +877,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return; } AppErrorResult res = (AppErrorResult) data.get("result"); - if (!mSleeping) { + if (!mSleeping && !mShuttingDown) { Dialog d = new AppErrorDialog( mContext, res, proc, (Integer)data.get("flags"), @@ -1046,7 +1062,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ApplicationInfo info = mSelf.mContext.getPackageManager().getApplicationInfo( - "android", PackageManager.GET_SHARED_LIBRARY_FILES); + "android", STOCK_PM_FLAGS); synchronized (mSelf) { ProcessRecord app = mSelf.newProcessRecordLocked( mSystemThread.getApplicationThread(), info, @@ -1270,7 +1286,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mBatteryStatsService.getActiveStatistics().writeLocked(); mUsageStatsService = new UsageStatsService( new File( - systemDir, "usagestats.bin").toString()); + systemDir, "usagestats").toString()); mConfiguration.makeDefault(); mProcessStats.init(); @@ -1635,6 +1651,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (r.startTime == 0) { r.startTime = SystemClock.uptimeMillis(); + if (mInitialStartTime == 0) { + mInitialStartTime = r.startTime; + } + } else if (mInitialStartTime == 0) { + mInitialStartTime = SystemClock.uptimeMillis(); } if (app != null && app.thread != null) { @@ -1785,7 +1806,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Watchdog.getInstance().processStarted(app, app.processName, pid); } - StringBuilder buf = new StringBuilder(128); + StringBuilder buf = mStringBuilder; + buf.setLength(0); buf.append("Start proc "); buf.append(app.processName); buf.append(" for "); @@ -1880,7 +1902,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If we are not going to sleep, we want to ensure the device is // awake until the next activity is started. - if (!mSleeping) { + if (!mSleeping && !mShuttingDown) { mLaunchingActivity.acquire(); if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) { // To be safe, don't allow the wake lock to be held for too long. @@ -1959,12 +1981,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mPausingActivity = null; } - if (!mSleeping) { + if (!mSleeping && !mShuttingDown) { resumeTopActivityLocked(prev); } else { if (mGoingToSleep.isHeld()) { mGoingToSleep.release(); } + if (mShuttingDown) { + notifyAll(); + } } if (prev != null) { @@ -2203,7 +2228,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } ActivityInfo aInfo = intent.resolveActivityInfo(mContext.getPackageManager(), - PackageManager.GET_SHARED_LIBRARY_FILES); + STOCK_PM_FLAGS); if (aInfo != null) { intent.setComponent(new ComponentName( aInfo.applicationInfo.packageName, aInfo.name)); @@ -2230,7 +2255,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If we are sleeping, and there is no resumed activity, and the top // activity is paused, well that is the state we want. - if (mSleeping && mLastPausedActivity == next && next.state == ActivityState.PAUSED) { + if ((mSleeping || mShuttingDown) + && mLastPausedActivity == next && next.state == ActivityState.PAUSED) { // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. mWindowManager.executeAppTransition(); @@ -2813,7 +2839,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen HistoryRecord r = new HistoryRecord(this, callerApp, callingUid, intent, resolvedType, aInfo, mConfiguration, resultRecord, resultWho, requestCode, componentSpecified); - r.startTime = SystemClock.uptimeMillis(); HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null; @@ -3160,7 +3185,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ActivityThread.getPackageManager().resolveIntent( intent, resolvedType, PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.GET_SHARED_LIBRARY_FILES); + | STOCK_PM_FLAGS); aInfo = rInfo != null ? rInfo.activityInfo : null; } catch (RemoteException e) { aInfo = null; @@ -3221,8 +3246,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen List resolves = ActivityThread.getPackageManager().queryIntentActivities( intent, r.resolvedType, - PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.GET_SHARED_LIBRARY_FILES); + PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS); // Look for the original activity in the list... final int N = resolves != null ? resolves.size() : 0; @@ -3304,8 +3328,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ResolveInfo rInfo = ActivityThread.getPackageManager().resolveIntent( intent, resolvedType, - PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.GET_SHARED_LIBRARY_FILES); + PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS); aInfo = rInfo != null ? rInfo.activityInfo : null; } catch (RemoteException e) { aInfo = null; @@ -4095,7 +4118,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - StringBuilder info = new StringBuilder(); + StringBuilder info = mStringBuilder; + info.setLength(0); info.append("ANR (application not responding) in process: "); info.append(app.processName); if (annotation != null) { @@ -4517,7 +4541,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } else if (mStartingProcesses.size() > 0) { app = mStartingProcesses.remove(0); - app.pid = pid; + app.setPid(pid); } else { app = null; } @@ -4586,7 +4610,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mWaitForDebugger = mOrigWaitForDebugger; } } - thread.bindApplication(processName, app.info, providers, + thread.bindApplication(processName, app.instrumentationInfo != null + ? app.instrumentationInfo : app.info, providers, app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, mConfiguration, getCommonServicesLocked()); @@ -6629,8 +6654,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen try { providers = ActivityThread.getPackageManager(). queryContentProviders(app.processName, app.info.uid, - PackageManager.GET_SHARED_LIBRARY_FILES - | PackageManager.GET_URI_PERMISSION_PATTERNS); + STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); } catch (RemoteException ex) { } if (providers != null) { @@ -6734,7 +6758,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else { try { cpi = ActivityThread.getPackageManager(). - resolveContentProvider(name, PackageManager.GET_URI_PERMISSION_PATTERNS); + resolveContentProvider(name, + STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); } catch (RemoteException ex) { } if (cpi == null) { @@ -6755,7 +6780,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ActivityThread.getPackageManager(). getApplicationInfo( cpi.applicationInfo.packageName, - PackageManager.GET_SHARED_LIBRARY_FILES); + STOCK_PM_FLAGS); if (ai == null) { Log.w(TAG, "No package info for content provider " + cpi.name); @@ -7085,8 +7110,45 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + public boolean shutdown(int timeout) { + if (checkCallingPermission(android.Manifest.permission.SHUTDOWN) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.SHUTDOWN); + } + + boolean timedout = false; + + synchronized(this) { + mShuttingDown = true; + mWindowManager.setEventDispatching(false); + + if (mResumedActivity != null) { + pauseIfSleepingLocked(); + final long endTime = System.currentTimeMillis() + timeout; + while (mResumedActivity != null || mPausingActivity != null) { + long delay = endTime - System.currentTimeMillis(); + if (delay <= 0) { + Log.w(TAG, "Activity manager shutdown timed out"); + timedout = true; + break; + } + try { + this.wait(); + } catch (InterruptedException e) { + } + } + } + } + + mUsageStatsService.shutdown(); + mBatteryStatsService.shutdown(); + + return timedout; + } + void pauseIfSleepingLocked() { - if (mSleeping) { + if (mSleeping || mShuttingDown) { if (!mGoingToSleep.isHeld()) { mGoingToSleep.acquire(); if (mLaunchingActivity.isHeld()) { @@ -7454,7 +7516,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { ResolveInfo ri = mContext.getPackageManager() .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST), - 0); + STOCK_PM_FLAGS); CharSequence errorMsg = null; if (ri != null) { ActivityInfo ai = ri.activityInfo; @@ -7490,7 +7552,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try { List apps = ActivityThread.getPackageManager(). - getPersistentApplications(PackageManager.GET_SHARED_LIBRARY_FILES); + getPersistentApplications(STOCK_PM_FLAGS); if (apps != null) { int N = apps.size(); int i; @@ -7877,24 +7939,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return; } pw.println("Activities in Current Activity Manager State:"); - dumpHistoryList(pw, mHistory, " ", "History"); + dumpHistoryList(pw, mHistory, " ", "Hist", true); pw.println(" "); pw.println(" Running activities (most recent first):"); - dumpHistoryList(pw, mLRUActivities, " ", "Running"); + dumpHistoryList(pw, mLRUActivities, " ", "Run", false); if (mWaitingVisibleActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting for another to become visible:"); - dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Waiting"); + dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false); } if (mStoppingActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting to stop:"); - dumpHistoryList(pw, mStoppingActivities, " ", "Stopping"); + dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false); } if (mFinishingActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting to finish:"); - dumpHistoryList(pw, mFinishingActivities, " ", "Finishing"); + dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false); } pw.println(" "); @@ -7909,7 +7971,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen final int N = mRecentTasks.size(); for (int i=0; i 0) { @@ -7984,7 +8049,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen needSep = true; pw.println(" Processes that are starting:"); dumpProcessList(pw, mStartingProcesses, " ", - "Starting Norm Proc", "Starting PERS Proc", false); + "Starting Norm", "Starting PERS", false); } if (mRemovedProcesses.size() > 0) { @@ -7992,7 +8057,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen needSep = true; pw.println(" Processes that are being removed:"); dumpProcessList(pw, mRemovedProcesses, " ", - "Removed Norm Proc", "Removed PERS Proc", false); + "Removed Norm", "Removed PERS", false); } if (mProcessesOnHold.size() > 0) { @@ -8000,7 +8065,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen needSep = true; pw.println(" Processes that are on old until the system is ready:"); dumpProcessList(pw, mProcessesOnHold, " ", - "OnHold Norm Proc", "OnHold PERS Proc", false); + "OnHold Norm", "OnHold PERS", false); } if (mProcessCrashTimes.getMap().size() > 0) { @@ -8013,10 +8078,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen SparseArray uids = procs.getValue(); final int N = uids.size(); for (int i=0; i uids = procs.getValue(); final int N = uids.size(); for (int i=0; i 0 || mOrderedBroadcasts.size() > 0 || mPendingBroadcast != null) { @@ -8172,13 +8239,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (mStickyBroadcasts != null) { pw.println(" "); pw.println(" Sticky broadcasts:"); + StringBuilder sb = new StringBuilder(128); for (Map.Entry> ent : mStickyBroadcasts.entrySet()) { - pw.println(" Sticky action " + ent.getKey() + ":"); + pw.print(" * Sticky action "); pw.print(ent.getKey()); + pw.println(":"); ArrayList intents = ent.getValue(); final int N = intents.size(); for (int i=0; i it = mServices.values().iterator(); while (it.hasNext()) { ServiceRecord r = it.next(); - pw.println(" Service " + r.shortName); + pw.print(" * "); pw.println(r); r.dump(pw, " "); } needSep = true; @@ -8220,7 +8297,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen pw.println(" Pending services:"); for (int i=0; i " + r.conn.asBinder()); + pw.print(" * "); pw.println(r); r.dump(pw, " "); } } @@ -8279,27 +8355,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen boolean needSep = false; - if (mProvidersByName.size() > 0) { - pw.println(" Published content providers (by name):"); - Iterator it = mProvidersByName.entrySet().iterator(); + if (mProvidersByClass.size() > 0) { + if (needSep) pw.println(" "); + pw.println(" Published content providers (by class):"); + Iterator it = mProvidersByClass.entrySet().iterator(); while (it.hasNext()) { Map.Entry e = (Map.Entry)it.next(); ContentProviderRecord r = (ContentProviderRecord)e.getValue(); - pw.println(" Provider " + (String)e.getKey()); + pw.print(" * "); pw.println(r); r.dump(pw, " "); } needSep = true; } - if (mProvidersByClass.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Published content providers (by class):"); - Iterator it = mProvidersByClass.entrySet().iterator(); + if (mProvidersByName.size() > 0) { + pw.println(" "); + pw.println(" Authority to provider mappings:"); + Iterator it = mProvidersByName.entrySet().iterator(); while (it.hasNext()) { Map.Entry e = (Map.Entry)it.next(); ContentProviderRecord r = (ContentProviderRecord)e.getValue(); - pw.println(" Provider " + (String)e.getKey()); - r.dump(pw, " "); + pw.print(" "); pw.print(e.getKey()); pw.print(": "); + pw.println(r); } needSep = true; } @@ -8308,21 +8385,25 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (needSep) pw.println(" "); pw.println(" Launching content providers:"); for (int i=mLaunchingProviders.size()-1; i>=0; i--) { - pw.println(" Provider #" + i + ":"); - ((ContentProviderRecord)mLaunchingProviders.get(i)).dump(pw, " "); + pw.print(" Launching #"); pw.print(i); pw.print(": "); + pw.println(mLaunchingProviders.get(i)); } needSep = true; } - pw.println(); - pw.println("Granted Uri Permissions:"); - for (int i=0; i perms - = mGrantedUriPermissions.valueAt(i); - pw.println(" Uris granted to uid " + uid + ":"); - for (UriPermission perm : perms.values()) { - perm.dump(pw, " "); + if (mGrantedUriPermissions.size() > 0) { + pw.println(); + pw.println("Granted Uri Permissions:"); + for (int i=0; i perms + = mGrantedUriPermissions.valueAt(i); + pw.print(" * UID "); pw.print(uid); + pw.println(" holds:"); + for (UriPermission perm : perms.values()) { + pw.print(" "); pw.println(perm); + perm.dump(pw, " "); + } } } } @@ -8340,7 +8421,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return; } - pw.println("Intent Senders in Current Activity Manager State:"); + pw.println("Pending Intents in Current Activity Manager State:"); if (this.mIntentSenderRecords.size() > 0) { Iterator> it @@ -8349,10 +8430,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen WeakReference ref = it.next(); PendingIntentRecord rec = ref != null ? ref.get(): null; if (rec != null) { - pw.println(" IntentSender " + rec); + pw.print(" * "); pw.println(rec); rec.dump(pw, " "); } else { - pw.println(" IntentSender " + ref); + pw.print(" * "); pw.print(ref); } } } @@ -8360,16 +8441,26 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } private static final void dumpHistoryList(PrintWriter pw, List list, - String prefix, String label) { + String prefix, String label, boolean complete) { TaskRecord lastTask = null; for (int i=list.size()-1; i>=0; i--) { HistoryRecord r = (HistoryRecord)list.get(i); + final boolean full = complete || !r.inHistory; if (lastTask != r.task) { lastTask = r.task; - lastTask.dump(pw, prefix + " "); + pw.print(prefix); + pw.print(full ? "* " : " "); + pw.println(lastTask); + if (full) { + lastTask.dump(pw, prefix + " "); + } + } + pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label); + pw.print(" #"); pw.print(i); pw.print(": "); + pw.println(r); + if (full) { + r.dump(pw, prefix + " "); } - pw.println(prefix + " " + label + " #" + i + ":"); - r.dump(pw, prefix + " "); } } @@ -8401,7 +8492,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private static final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, List list, String prefix, String[] args) { - final boolean isCheckinRequest = scanArgs(args, "-c"); + final boolean isCheckinRequest = scanArgs(args, "--checkin"); long uptime = SystemClock.uptimeMillis(); long realtime = SystemClock.elapsedRealtime(); @@ -8738,7 +8829,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mPidsSelfLocked.remove(app.pid); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } - app.pid = 0; + app.setPid(0); } } @@ -8876,7 +8967,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen try { ResolveInfo rInfo = ActivityThread.getPackageManager().resolveService( - service, resolvedType, PackageManager.GET_SHARED_LIBRARY_FILES); + service, resolvedType, STOCK_PM_FLAGS); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; if (sInfo == null) { @@ -10094,7 +10185,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (intent.getComponent() != null) { // Broadcast is going to one specific receiver class... ActivityInfo ai = ActivityThread.getPackageManager(). - getReceiverInfo(intent.getComponent(), 0); + getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS); if (ai != null) { receivers = new ArrayList(); ResolveInfo ri = new ResolveInfo(); @@ -10107,7 +10198,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen == 0) { receivers = ActivityThread.getPackageManager().queryIntentReceivers( - intent, resolvedType, PackageManager.GET_SHARED_LIBRARY_FILES); + intent, resolvedType, STOCK_PM_FLAGS); } registeredReceivers = mReceiverResolver.queryIntent(resolver, intent, resolvedType, false); @@ -10844,9 +10935,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ApplicationInfo ai = null; try { ii = mContext.getPackageManager().getInstrumentationInfo( - className, 0); + className, STOCK_PM_FLAGS); ai = mContext.getPackageManager().getApplicationInfo( - ii.targetPackage, PackageManager.GET_SHARED_LIBRARY_FILES); + ii.targetPackage, STOCK_PM_FLAGS); } catch (PackageManager.NameNotFoundException e) { } if (ii == null) { @@ -10878,6 +10969,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen uninstallPackageLocked(ii.targetPackage, -1, true); ProcessRecord app = addAppLocked(ai); app.instrumentationClass = className; + app.instrumentationInfo = ai; app.instrumentationProfileFile = profileFile; app.instrumentationArguments = arguments; app.instrumentationWatcher = watcher; @@ -10925,6 +11017,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } app.instrumentationWatcher = null; app.instrumentationClass = null; + app.instrumentationInfo = null; app.instrumentationProfileFile = null; app.instrumentationArguments = null; diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/java/com/android/server/am/AppBindRecord.java index ce6f6dcb4fdd0793e95b6e082080d960707922ec..9c57360a850712eb872ecab6282047f6da2bdaf6 100644 --- a/services/java/com/android/server/am/AppBindRecord.java +++ b/services/java/com/android/server/am/AppBindRecord.java @@ -32,9 +32,12 @@ class AppBindRecord { // All ConnectionRecord for this client. void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); pw.println(prefix + "service=" + service); pw.println(prefix + "client=" + client); + dumpInIntentBind(pw, prefix); + } + + void dumpInIntentBind(PrintWriter pw, String prefix) { if (connections.size() > 0) { pw.println(prefix + "Per-process Connections:"); Iterator it = connections.iterator(); diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index 9ad994c52c1d02d9bd73c2ec65e336351a53cd4e..0387be5285fdc21d8b47c854d061f9476ec4ab70 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -25,8 +25,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Process; import android.os.ServiceManager; -import android.telephony.TelephonyManager; -import android.util.PrintWriterPrinter; +import android.util.Log; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -50,6 +49,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub { ServiceManager.addService("batteryinfo", asBinder()); } + public void shutdown() { + Log.w("BatteryStats", "Writing battery stats before shutdown..."); + synchronized (mStats) { + mStats.writeLocked(); + } + } + public static IBatteryStats getService() { if (sService != null) { return sService; @@ -255,6 +261,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } + public void noteWifiMulticastEnabled(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteWifiMulticastEnabledLocked(uid); + } + } + + public void noteWifiMulticastDisabled(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteWifiMulticastDisabledLocked(uid); + } + } + public boolean isOnBattery() { return mStats.isOnBattery(); } @@ -264,6 +284,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub { mStats.setOnBattery(onBattery, level); } + public void recordCurrentLevel(int level) { + enforceCallingPermission(); + mStats.recordCurrentLevel(level); + } + public long getAwakeTimeBattery() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BATTERY_STATS, null); @@ -290,14 +315,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub { boolean isCheckin = false; if (args != null) { for (String arg : args) { - if ("-c".equals(arg)) { + if ("--checkin".equals(arg)) { isCheckin = true; break; } } } if (isCheckin) mStats.dumpCheckinLocked(pw, args); - else mStats.dumpLocked(new PrintWriterPrinter(pw)); + else mStats.dumpLocked(pw); } } } diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java index cd7f7202586475cc0878707ddb40b2ed651d80c1..0eeb3931093db5b32a613cb8eecd2f73153926f5 100644 --- a/services/java/com/android/server/am/BroadcastFilter.java +++ b/services/java/com/android/server/am/BroadcastFilter.java @@ -18,6 +18,7 @@ package com.android.server.am; import android.content.IntentFilter; import android.util.PrintWriterPrinter; +import android.util.Printer; import java.io.PrintWriter; @@ -33,19 +34,25 @@ class BroadcastFilter extends IntentFilter { requiredPermission = _requiredPermission; } - public void dumpLocal(PrintWriter pw, String prefix) { - super.dump(new PrintWriterPrinter(pw), prefix); - } - public void dump(PrintWriter pw, String prefix) { - dumpLocal(pw, prefix); - pw.println(prefix + "requiredPermission=" + requiredPermission); + dumpInReceiverList(pw, new PrintWriterPrinter(pw), prefix); receiverList.dumpLocal(pw, prefix); } + public void dumpInReceiverList(PrintWriter pw, Printer pr, String prefix) { + super.dump(pr, prefix); + if (requiredPermission != null) { + pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission); + } + } + public String toString() { - return "BroadcastFilter{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + receiverList + "}"; + StringBuilder sb = new StringBuilder(); + sb.append("BroadcastFilter{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(receiverList); + sb.append('}'); + return sb.toString(); } } diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java index 41a783f67b04b61069f2e46901bb3747e59cae1f..b3343dd51eb25f75801fbe2cf184069709c701e1 100644 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ b/services/java/com/android/server/am/ConnectionRecord.java @@ -28,11 +28,13 @@ class ConnectionRecord { final HistoryRecord activity; // If non-null, the owning activity. final IServiceConnection conn; // The client connection. final int flags; // Binding options. - + String stringName; // Caching of toString. + void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); pw.println(prefix + "binding=" + binding); - pw.println(prefix + "activity=" + activity); + if (activity != null) { + pw.println(prefix + "activity=" + activity); + } pw.println(prefix + "conn=" + conn.asBinder() + " flags=0x" + Integer.toHexString(flags)); } @@ -46,9 +48,17 @@ class ConnectionRecord { } public String toString() { - return "ConnectionRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + binding.service.shortName - + ":@" + Integer.toHexString(System.identityHashCode(conn.asBinder())) + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("ConnectionRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(binding.service.shortName); + sb.append(":@"); + sb.append(Integer.toHexString(System.identityHashCode(conn.asBinder()))); + sb.append('}'); + return stringName = sb.toString(); } } diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java index 9f37c140bcbeb5bc77f282da23e0f57e777a738a..c764635fa79d48983b5409c6106940629698b3e3 100644 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ b/services/java/com/android/server/am/ContentProviderRecord.java @@ -32,7 +32,8 @@ class ContentProviderRecord extends ContentProviderHolder { int externals; // number of non-framework processes supported by this provider ProcessRecord app; // if non-null, hosting application ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. - + String stringName; + public ContentProviderRecord(ProviderInfo _info, ApplicationInfo ai) { super(_info); uid = ai.uid; @@ -53,24 +54,39 @@ class ContentProviderRecord extends ContentProviderHolder { } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "package=" + info.applicationInfo.packageName - + " process=" + info.processName); - pw.println(prefix + "app=" + app); - pw.println(prefix + "launchingApp=" + launchingApp); - pw.println(prefix + "provider=" + provider); - pw.println(prefix + "name=" + info.authority); - pw.println(prefix + "isSyncable=" + info.isSyncable); - pw.println(prefix + "multiprocess=" + info.multiprocess - + " initOrder=" + info.initOrder - + " uid=" + uid); - pw.println(prefix + "clients=" + clients); - pw.println(prefix + "externals=" + externals); + pw.print(prefix); pw.print("package="); + pw.print(info.applicationInfo.packageName); + pw.print("process="); pw.println(info.processName); + pw.print(prefix); pw.print("app="); pw.println(app); + if (launchingApp != null) { + pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp); + } + pw.print(prefix); pw.print("uid="); pw.print(uid); + pw.print(" provider="); pw.println(provider); + pw.print(prefix); pw.print("name="); pw.println(info.authority); + if (info.isSyncable || info.multiprocess || info.initOrder != 0) { + pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable); + pw.print("multiprocess="); pw.print(info.multiprocess); + pw.print(" initOrder="); pw.println(info.initOrder); + } + if (clients.size() > 0) { + pw.print(prefix); pw.print("clients="); pw.println(clients); + } + if (externals != 0) { + pw.print(prefix); pw.print("externals="); pw.println(externals); + } } public String toString() { - return "ContentProviderRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + info.name + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("ContentProviderRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(info.name); + sb.append('}'); + return stringName = sb.toString(); } } diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java index 0f62471ed7d312538271cca50acd4c2e9a6e61c9..14887910cdbd1eecce86f87f4a8e210e568b72cd 100644 --- a/services/java/com/android/server/am/HistoryRecord.java +++ b/services/java/com/android/server/am/HistoryRecord.java @@ -100,46 +100,74 @@ class HistoryRecord extends IApplicationToken.Stub { boolean hasBeenLaunched;// has this activity ever been launched? boolean frozenBeforeDestroy;// has been frozen but not yet destroyed. + String stringName; // for caching of toString(). + void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "packageName=" + packageName - + " processName=" + processName); - pw.println(prefix + "launchedFromUid=" + launchedFromUid - + " app=" + app); - pw.println(prefix + intent); - pw.println(prefix + "frontOfTask=" + frontOfTask + " task=" + task); - pw.println(prefix + "taskAffinity=" + taskAffinity); - pw.println(prefix + "realActivity=" + realActivity); - pw.println(prefix + "dir=" + baseDir + " res=" + resDir + " data=" + dataDir); - pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) - + " icon=0x" + Integer.toHexString(icon) - + " theme=0x" + Integer.toHexString(theme)); - pw.println(prefix + "stateNotNeeded=" + stateNotNeeded - + " componentSpecified=" + componentSpecified - + " isHomeActivity=" + isHomeActivity); - pw.println(prefix + "configuration=" + configuration); - pw.println(prefix + "resultTo=" + resultTo - + " resultWho=" + resultWho + " resultCode=" + requestCode); - pw.println(prefix + "results=" + results); - pw.println(prefix + "pendingResults=" + pendingResults); - pw.println(prefix + "readUriPermissions=" + readUriPermissions); - pw.println(prefix + "writeUriPermissions=" + writeUriPermissions); - pw.println(prefix + "launchFailed=" + launchFailed - + " haveState=" + haveState + " icicle=" + icicle); - pw.println(prefix + "state=" + state - + " stopped=" + stopped + " finishing=" + finishing); - pw.println(prefix + "keysPaused=" + keysPaused - + " inHistory=" + inHistory + " persistent=" + persistent - + " launchMode=" + launchMode); - pw.println(prefix + "fullscreen=" + fullscreen - + " visible=" + visible - + " frozenBeforeDestroy=" + frozenBeforeDestroy - + " thumbnailNeeded=" + thumbnailNeeded + " idle=" + idle); - pw.println(prefix + "waitingVisible=" + waitingVisible - + " nowVisible=" + nowVisible); - pw.println(prefix + "configDestroy=" + configDestroy - + " configChangeFlags=" + Integer.toHexString(configChangeFlags)); - pw.println(prefix + "connections=" + connections); + pw.print(prefix); pw.print("packageName="); pw.print(packageName); + pw.print(" processName="); pw.println(processName); + pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid); + pw.print(" app="); pw.println(app); + pw.print(prefix); pw.println(intent); + pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask); + pw.print(" task="); pw.println(task); + pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity); + pw.print(prefix); pw.print("realActivity="); + pw.println(realActivity.flattenToShortString()); + pw.print(prefix); pw.print("base="); pw.print(baseDir); + if (!resDir.equals(baseDir)) pw.print(" res="); pw.print(resDir); + pw.print(" data="); pw.println(dataDir); + pw.print(prefix); pw.print("labelRes=0x"); + pw.print(Integer.toHexString(labelRes)); + pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); + pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); + pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); + pw.print(" componentSpecified="); pw.print(componentSpecified); + pw.print(" isHomeActivity="); pw.println(isHomeActivity); + pw.print(prefix); pw.print("configuration="); pw.println(configuration); + if (resultTo != null || resultWho != null) { + pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); + pw.print(" resultWho="); pw.print(resultWho); + pw.print(" resultCode="); pw.println(requestCode); + } + if (results != null) { + pw.print(prefix); pw.print("results="); pw.println(results); + } + if (pendingResults != null) { + pw.print(prefix); pw.print("pendingResults="); pw.println(pendingResults); + } + if (readUriPermissions != null) { + pw.print(prefix); pw.print("readUriPermissions="); pw.println(readUriPermissions); + } + if (writeUriPermissions != null) { + pw.print(prefix); pw.print("writeUriPermissions="); pw.println(writeUriPermissions); + } + pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed); + pw.print(" haveState="); pw.print(haveState); + pw.print(" icicle="); pw.println(icicle); + pw.print(prefix); pw.print("state="); pw.print(state); + pw.print(" stopped="); pw.print(stopped); + pw.print(" finishing="); pw.println(finishing); + pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); + pw.print(" inHistory="); pw.print(inHistory); + pw.print(" persistent="); pw.print(persistent); + pw.print(" launchMode="); pw.println(launchMode); + pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen); + pw.print(" visible="); pw.print(visible); + pw.print(" frozenBeforeDestroy="); pw.print(frozenBeforeDestroy); + pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded); + pw.print(" idle="); pw.println(idle); + if (waitingVisible || nowVisible) { + pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible); + pw.print(" nowVisible="); pw.println(nowVisible); + } + if (configDestroy || configChangeFlags != 0) { + pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy); + pw.print(" configChangeFlags="); + pw.println(Integer.toHexString(configChangeFlags)); + } + if (connections != null) { + pw.print(prefix); pw.print("connections="); pw.println(connections); + } } HistoryRecord(ActivityManagerService _service, ProcessRecord _caller, @@ -335,15 +363,31 @@ class HistoryRecord extends IApplicationToken.Stub { public void windowsVisible() { synchronized(service) { - if (ActivityManagerService.SHOW_ACTIVITY_START_TIME - && startTime != 0) { - long time = SystemClock.uptimeMillis() - startTime; - EventLog.writeEvent(ActivityManagerService.LOG_ACTIVITY_LAUNCH_TIME, - System.identityHashCode(this), shortComponentName, time); - Log.i(ActivityManagerService.TAG, "Displayed activity " - + shortComponentName - + ": " + time + " ms"); + if (startTime != 0) { + final long curTime = SystemClock.uptimeMillis(); + final long thisTime = curTime - startTime; + final long totalTime = service.mInitialStartTime != 0 + ? (curTime - service.mInitialStartTime) : thisTime; + if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) { + EventLog.writeEvent(ActivityManagerService.LOG_ACTIVITY_LAUNCH_TIME, + System.identityHashCode(this), shortComponentName, + thisTime, totalTime); + StringBuilder sb = service.mStringBuilder; + sb.setLength(0); + sb.append("Displayed activity "); + sb.append(shortComponentName); + sb.append(": "); + sb.append(thisTime); + sb.append(" ms (total "); + sb.append(totalTime); + sb.append(" ms)"); + Log.i(ActivityManagerService.TAG, sb.toString()); + } + if (totalTime > 0) { + service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime); + } startTime = 0; + service.mInitialStartTime = 0; } if (ActivityManagerService.DEBUG_SWITCH) Log.v( ActivityManagerService.TAG, "windowsVisible(): " + this); @@ -453,8 +497,15 @@ class HistoryRecord extends IApplicationToken.Stub { public String toString() { - return "HistoryRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + intent.getComponent().toShortString() + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("HistoryRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(intent.getComponent().flattenToShortString()); + sb.append('}'); + return stringName = sb.toString(); } } diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java index 24c3943aa5ad54f4296fd52b31b7d4b80b4e8cb1..3a5ca669c827c305c71ea6009df44cea4cc34261 100644 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ b/services/java/com/android/server/am/IntentBindRecord.java @@ -45,22 +45,30 @@ class IntentBindRecord { /** Set when the service's onUnbind() has asked to be told about new clients. */ boolean doRebind; + String stringName; // caching of toString + void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "service=" + service); - pw.println(prefix + "intent=" + intent.getIntent()); - pw.println(prefix + "binder=" + binder - + " requested=" + requested - + " received=" + received - + " hasBound=" + hasBound - + " doRebind=" + doRebind); + pw.print(prefix); pw.print("service="); pw.println(service); + dumpInService(pw, prefix); + } + + void dumpInService(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("intent={"); + pw.print(intent.getIntent().toShortString(true, false)); + pw.println('}'); + pw.print(prefix); pw.print("binder="); pw.println(binder); + pw.print(prefix); pw.print("requested="); pw.print(requested); + pw.print(" received="); pw.print(received); + pw.print(" hasBound="); pw.print(hasBound); + pw.print(" doRebind="); pw.println(doRebind); if (apps.size() > 0) { - pw.println(prefix + "Application Bindings:"); Iterator it = apps.values().iterator(); while (it.hasNext()) { AppBindRecord a = it.next(); - pw.println(prefix + "Client " + a.client); - a.dump(pw, prefix + " "); + pw.print(prefix); pw.print("* Client AppBindRecord{"); + pw.print(Integer.toHexString(System.identityHashCode(a))); + pw.print(' '); pw.print(a.client); pw.println('}'); + a.dumpInIntentBind(pw, prefix + " "); } } } @@ -71,9 +79,19 @@ class IntentBindRecord { } public String toString() { - return "IntentBindRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + service.name.toShortString() - + ":" + intent + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("IntentBindRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(service.shortName); + sb.append(':'); + if (intent != null) { + intent.getIntent().toShortString(sb, false, false); + } + sb.append('}'); + return stringName = sb.toString(); } } diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java index b18aaf7ed2815771c7362bd12e0c7c5e5d125782..43813928225541c977c3815a88e747d4f5881852 100644 --- a/services/java/com/android/server/am/PendingIntentRecord.java +++ b/services/java/com/android/server/am/PendingIntentRecord.java @@ -36,6 +36,8 @@ class PendingIntentRecord extends IIntentSender.Stub { boolean sent = false; boolean canceled = false; + String stringName; + final static class Key { final int type; final String packageName; @@ -142,7 +144,7 @@ class PendingIntentRecord extends IIntentSender.Stub { public String toString() { return "Key{" + typeName() + " pkg=" + packageName - + " intent=" + requestIntent + " flags=0x" + + " intent=" + requestIntent.toShortString(true, false) + " flags=0x" + Integer.toHexString(flags) + "}"; } @@ -260,19 +262,38 @@ class PendingIntentRecord extends IIntentSender.Stub { } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "packageName=" + key.packageName - + " type=" + key.typeName() - + " flags=0x" + Integer.toHexString(key.flags)); - pw.println(prefix + "activity=" + key.activity + " who=" + key.who); - pw.println(prefix + "requestCode=" + key.requestCode - + " requestResolvedType=" + key.requestResolvedType); - pw.println(prefix + "requestIntent=" + key.requestIntent); - pw.println(prefix + "sent=" + sent + " canceled=" + canceled); + pw.print(prefix); pw.print("uid="); pw.print(uid); + pw.print(" packageName="); pw.print(key.packageName); + pw.print(" type="); pw.print(key.typeName()); + pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags)); + if (key.activity != null || key.who != null) { + pw.print(prefix); pw.print("activity="); pw.print(key.activity); + pw.print(" who="); pw.println(key.who); + } + if (key.requestCode != 0 || key.requestResolvedType != null) { + pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode); + pw.print(" requestResolvedType="); pw.println(key.requestResolvedType); + } + pw.print(prefix); pw.print("requestIntent="); + pw.println(key.requestIntent.toShortString(true, true)); + if (sent || canceled) { + pw.print(prefix); pw.print("sent="); pw.print(sent); + pw.print(" canceled="); pw.println(canceled); + } } public String toString() { - return "IntentSenderRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + key.packageName + " " + key.typeName() + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("PendingIntentRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(key.packageName); + sb.append(' '); + sb.append(key.typeName()); + sb.append('}'); + return stringName = sb.toString(); } } diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index a1320dfec15aaea6ac0eead51db64bd8e12da2c7..68aebc3adc1a17ee8c69a3d272b25858c1fee35d 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -28,6 +28,7 @@ import android.content.pm.ApplicationInfo; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.util.PrintWriterPrinter; import java.io.PrintWriter; import java.util.ArrayList; @@ -62,6 +63,7 @@ class ProcessRecord implements Watchdog.PssRequestor { IBinder forcingToForeground;// Token that is forcing this process to be foreground int adjSeq; // Sequence id for identifying repeated trav ComponentName instrumentationClass;// class installed to instrument app + ApplicationInfo instrumentationInfo; // the application being instrumented String instrumentationProfileFile; // where to save profiling IInstrumentationWatcher instrumentationWatcher; // who is waiting Bundle instrumentationArguments;// as given to us @@ -98,44 +100,86 @@ class ProcessRecord implements Watchdog.PssRequestor { boolean waitedForDebugger; // has process show wait for debugger dialog? Dialog waitDialog; // current wait for debugger dialog + String stringName; // caching of toString() result. + // These reports are generated & stored when an app gets into an error condition. // They will be "null" when all is OK. ActivityManager.ProcessErrorStateInfo crashingReport; ActivityManager.ProcessErrorStateInfo notRespondingReport; void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "class=" + info.className); - pw.println(prefix+"manageSpaceActivityName="+info.manageSpaceActivityName); - pw.println(prefix + "dir=" + info.sourceDir + " publicDir=" + info.publicSourceDir - + " data=" + info.dataDir); - pw.println(prefix + "packageList=" + pkgList); - pw.println(prefix + "instrumentationClass=" + instrumentationClass - + " instrumentationProfileFile=" + instrumentationProfileFile); - pw.println(prefix + "instrumentationArguments=" + instrumentationArguments); - pw.println(prefix + "thread=" + thread + " curReceiver=" + curReceiver); - pw.println(prefix + "pid=" + pid + " starting=" + starting - + " lastPss=" + lastPss); - pw.println(prefix + "maxAdj=" + maxAdj + " hiddenAdj=" + hiddenAdj - + " curRawAdj=" + curRawAdj + " setRawAdj=" + setRawAdj - + " curAdj=" + curAdj + " setAdj=" + setAdj); - pw.println(prefix + "isForeground=" + isForeground - + " setIsForeground=" + setIsForeground - + " foregroundServices=" + foregroundServices - + " forcingToForeground=" + forcingToForeground); - pw.println(prefix + "persistent=" + persistent + " removed=" + removed - + " persistentActivities=" + persistentActivities); - pw.println(prefix + "debugging=" + debugging - + " crashing=" + crashing + " " + crashDialog - + " notResponding=" + notResponding + " " + anrDialog - + " bad=" + bad); - pw.println(prefix + "activities=" + activities); - pw.println(prefix + "services=" + services); - pw.println(prefix + "executingServices=" + executingServices); - pw.println(prefix + "connections=" + connections); - pw.println(prefix + "pubProviders=" + pubProviders); - pw.println(prefix + "conProviders=" + conProviders); - pw.println(prefix + "receivers=" + receivers); + if (info.className != null) { + pw.print(prefix); pw.print("class="); pw.println(info.className); + } + if (info.manageSpaceActivityName != null) { + pw.print(prefix); pw.print("manageSpaceActivityName="); + pw.println(info.manageSpaceActivityName); + } + pw.print(prefix); pw.print("dir="); pw.print(info.sourceDir); + pw.print(" publicDir="); pw.print(info.publicSourceDir); + pw.print(" data="); pw.println(info.dataDir); + pw.print(prefix); pw.print("packageList="); pw.println(pkgList); + if (instrumentationClass != null || instrumentationProfileFile != null + || instrumentationArguments != null) { + pw.print(prefix); pw.print("instrumentationClass="); + pw.print(instrumentationClass); + pw.print(" instrumentationProfileFile="); + pw.println(instrumentationProfileFile); + pw.print(prefix); pw.print("instrumentationArguments="); + pw.println(instrumentationArguments); + pw.print(prefix); pw.print("instrumentationInfo="); + pw.println(instrumentationInfo); + if (instrumentationInfo != null) { + instrumentationInfo.dump(new PrintWriterPrinter(pw), prefix + " "); + } + } + pw.print(prefix); pw.print("thread="); pw.print(thread); + pw.print(" curReceiver="); pw.println(curReceiver); + pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting="); + pw.print(starting); pw.print(" lastPss="); pw.println(lastPss); + pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); + pw.print(" hidden="); pw.print(hiddenAdj); + pw.print(" curRaw="); pw.print(curRawAdj); + pw.print(" setRaw="); pw.print(setRawAdj); + pw.print(" cur="); pw.print(curAdj); + pw.print(" set="); pw.println(setAdj); + pw.print(prefix); pw.print("isForeground="); pw.print(isForeground); + pw.print(" setIsForeground="); pw.print(setIsForeground); + pw.print(" foregroundServices="); pw.print(foregroundServices); + pw.print(" forcingToForeground="); pw.println(forcingToForeground); + pw.print(prefix); pw.print("persistent="); pw.print(persistent); + pw.print(" removed="); pw.print(removed); + pw.print(" persistentActivities="); pw.println(persistentActivities); + if (debugging || crashing || crashDialog != null || notResponding + || anrDialog != null || bad) { + pw.print(prefix); pw.print("debugging="); pw.print(debugging); + pw.print(" crashing="); pw.print(crashing); + pw.print(" "); pw.print(crashDialog); + pw.print(" notResponding="); pw.print(notResponding); + pw.print(" " ); pw.print(anrDialog); + pw.print(" bad="); pw.println(bad); + } + if (activities.size() > 0) { + pw.print(prefix); pw.print("activities="); pw.println(activities); + } + if (services.size() > 0) { + pw.print(prefix); pw.print("services="); pw.println(services); + } + if (executingServices.size() > 0) { + pw.print(prefix); pw.print("executingServices="); pw.println(executingServices); + } + if (connections.size() > 0) { + pw.print(prefix); pw.print("connections="); pw.println(connections); + } + if (pubProviders.size() > 0) { + pw.print(prefix); pw.print("pubProviders="); pw.println(pubProviders); + } + if (conProviders.size() > 0) { + pw.print(prefix); pw.print("conProviders="); pw.println(conProviders); + } + if (receivers.size() > 0) { + pw.print(prefix); pw.print("receivers="); pw.println(receivers); + } } ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread, @@ -154,6 +198,11 @@ class ProcessRecord implements Watchdog.PssRequestor { persistentActivities = 0; } + public void setPid(int _pid) { + pid = _pid; + stringName = null; + } + /** * This method returns true if any of the activities within the process record are interesting * to the user. See HistoryRecord.isInterestingToUserLocked() @@ -188,9 +237,20 @@ class ProcessRecord implements Watchdog.PssRequestor { } public String toString() { - return "ProcessRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + pid + ":" + processName + "/" + info.uid + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("ProcessRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(pid); + sb.append(':'); + sb.append(processName); + sb.append('/'); + sb.append(info.uid); + sb.append('}'); + return stringName = sb.toString(); } /* diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java index 6ac527bd7ed2da0bff40df6ba7544f9dfd60ec3b..0facefc52d3a322e5fb792e48df78feec5700a48 100644 --- a/services/java/com/android/server/am/ReceiverList.java +++ b/services/java/com/android/server/am/ReceiverList.java @@ -18,9 +18,12 @@ package com.android.server.am; import android.app.IIntentReceiver; import android.content.Intent; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.util.PrintWriterPrinter; +import android.util.Printer; import java.io.PrintWriter; import java.util.ArrayList; @@ -39,6 +42,8 @@ class ReceiverList extends ArrayList BroadcastRecord curBroadcast = null; boolean linkedToDeath = false; + String stringName; + ReceiverList(ActivityManagerService _owner, ProcessRecord _app, int _pid, int _uid, IIntentReceiver _receiver) { owner = _owner; @@ -62,31 +67,45 @@ class ReceiverList extends ArrayList } void dumpLocal(PrintWriter pw, String prefix) { - pw.println(prefix + "receiver=IBinder " - + Integer.toHexString(System.identityHashCode(receiver.asBinder()))); - pw.println(prefix + "app=" + app + " pid=" + pid + " uid=" + uid); - pw.println(prefix + "curBroadcast=" + curBroadcast - + " linkedToDeath=" + linkedToDeath); + pw.print(prefix); pw.print("app="); pw.print(app); + pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.println(uid); + if (curBroadcast != null || linkedToDeath) { + pw.print(prefix); pw.print("curBroadcast="); pw.print(curBroadcast); + pw.print(" linkedToDeath="); pw.println(linkedToDeath); + } } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); + Printer pr = new PrintWriterPrinter(pw); dumpLocal(pw, prefix); String p2 = prefix + " "; final int N = size(); for (int i=0; i it = bindings.values().iterator(); while (it.hasNext()) { IntentBindRecord b = it.next(); - pw.println(prefix + "Binding " + b); - b.dump(pw, prefix + " "); + pw.print(prefix); pw.print("* IntentBindRecord{"); + pw.print(Integer.toHexString(System.identityHashCode(b))); + pw.println("}:"); + b.dumpInService(pw, prefix + " "); } } if (connections.size() > 0) { - pw.println(prefix + "All Connections:"); + pw.print(prefix); pw.println("All Connections:"); Iterator it = connections.values().iterator(); while (it.hasNext()) { ConnectionRecord c = it.next(); - pw.println(prefix + " " + c); + pw.print(prefix); pw.print(" "); pw.println(c); } } } @@ -159,8 +167,13 @@ class ServiceRecord extends Binder { } public String toString() { - return "ServiceRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + shortName + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("ServiceRecord{") + .append(Integer.toHexString(System.identityHashCode(this))) + .append(' ').append(shortName).append('}'); + return stringName = sb.toString(); } } diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index aab37367bfd3940cc6e7cbc44ba77befd8531c2c..bcb8f5406e65d4d9c799451a537a139b4094ce49 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -36,6 +36,8 @@ class TaskRecord { boolean rootWasReset; // True if the intent at the root of the task had // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. + String stringName; // caching of toString() result. + TaskRecord(int _taskId, ActivityInfo info, Intent _intent, boolean _clearOnBackground) { taskId = _taskId; @@ -53,6 +55,8 @@ class TaskRecord { } void setIntent(Intent _intent, ActivityInfo info) { + stringName = null; + if (info.targetActivity == null) { intent = _intent; realActivity = _intent != null ? _intent.getComponent() : null; @@ -82,23 +86,63 @@ class TaskRecord { } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "clearOnBackground=" + clearOnBackground - + " numActivities=" + numActivities - + " rootWasReset=" + rootWasReset); - pw.println(prefix + "affinity=" + affinity); - pw.println(prefix + "intent=" + intent); - pw.println(prefix + "affinityIntent=" + affinityIntent); - pw.println(prefix + "origActivity=" + origActivity); - pw.println(prefix + "lastActiveTime=" + lastActiveTime - +" (inactive for " + (getInactiveDuration()/1000) + "s)"); + if (clearOnBackground || numActivities != 0 || rootWasReset) { + pw.print(prefix); pw.print("clearOnBackground="); pw.print(clearOnBackground); + pw.print(" numActivities="); pw.print(numActivities); + pw.print(" rootWasReset="); pw.println(rootWasReset); + } + if (affinity != null) { + pw.print(prefix); pw.print("affinity="); pw.println(affinity); + } + if (intent != null) { + StringBuilder sb = new StringBuilder(128); + sb.append(prefix); sb.append("intent={"); + intent.toShortString(sb, true, false); + sb.append('}'); + pw.println(sb.toString()); + } + if (affinityIntent != null) { + StringBuilder sb = new StringBuilder(128); + sb.append(prefix); sb.append("affinityIntent={"); + affinityIntent.toShortString(sb, true, false); + sb.append('}'); + pw.println(sb.toString()); + } + if (origActivity != null) { + pw.print(prefix); pw.print("origActivity="); + pw.println(origActivity.flattenToShortString()); + } + if (realActivity != null) { + pw.print(prefix); pw.print("realActivity="); + pw.println(realActivity.flattenToShortString()); + } + pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); + pw.print(" (inactive for "); + pw.print((getInactiveDuration()/1000)); pw.println("s)"); } public String toString() { - return "Task{" + taskId + " " - + (affinity != null ? affinity - : (intent != null ? intent.getComponent().flattenToShortString() - : affinityIntent != null ? affinityIntent.getComponent().flattenToShortString() : "??")) - + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("TaskRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" #"); + sb.append(taskId); + if (affinity != null) { + sb.append(" A "); + sb.append(affinity); + } else if (intent != null) { + sb.append(" I "); + sb.append(intent.getComponent().flattenToShortString()); + } else if (affinityIntent != null) { + sb.append(" aI "); + sb.append(affinityIntent.getComponent().flattenToShortString()); + } else { + sb.append(" ??"); + } + sb.append('}'); + return stringName = sb.toString(); } } diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java index fb7a7458a8b25ba5d848c05f316679cd5e6d6e56..ffa8a2a495db82b9c6b4e8509a135503ba1261f5 100644 --- a/services/java/com/android/server/am/UriPermission.java +++ b/services/java/com/android/server/am/UriPermission.java @@ -30,6 +30,8 @@ class UriPermission { final HashSet readActivities = new HashSet(); final HashSet writeActivities = new HashSet(); + String stringName; + UriPermission(int _uid, Uri _uri) { uid = _uid; uri = _uri; @@ -65,18 +67,29 @@ class UriPermission { } public String toString() { - return "UriPermission{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + uri + "}"; + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("UriPermission{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(uri); + sb.append('}'); + return stringName = sb.toString(); } void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + " modeFlags=0x" + Integer.toHexString(modeFlags) - + " uid=" + uid - + " globalModeFlags=0x" - + Integer.toHexString(globalModeFlags)); - pw.println(prefix + " readActivities=" + readActivities); - pw.println(prefix + " writeActivities=" + writeActivities); + pw.print(prefix); pw.print("modeFlags=0x"); + pw.print(Integer.toHexString(modeFlags)); + pw.print(" uid="); pw.print(uid); + pw.print(" globalModeFlags=0x"); + pw.println(Integer.toHexString(globalModeFlags)); + if (readActivities.size() != 0) { + pw.print(prefix); pw.print("readActivities="); pw.println(readActivities); + } + if (writeActivities.size() != 0) { + pw.print(prefix); pw.print("writeActivities="); pw.println(writeActivities); + } } } diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java index 3922f39f52ba0a37dcdf3d829700180b3db6f8c2..866334b2d28ec36e1475ca5858044d208eb94cac 100755 --- a/services/java/com/android/server/am/UsageStatsService.java +++ b/services/java/com/android/server/am/UsageStatsService.java @@ -17,6 +17,7 @@ package com.android.server.am; import com.android.internal.app.IUsageStats; + import android.content.ComponentName; import android.content.Context; import android.os.Binder; @@ -37,11 +38,11 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TimeZone; /** * This service collects the statistics associated with usage @@ -53,6 +54,23 @@ public final class UsageStatsService extends IUsageStats.Stub { public static final String SERVICE_NAME = "usagestats"; private static final boolean localLOGV = false; private static final String TAG = "UsageStats"; + + // Current on-disk Parcel version + private static final int VERSION = 1004; + + private static final int CHECKIN_VERSION = 3; + + private static final String FILE_PREFIX = "usage-"; + + private static final int FILE_WRITE_INTERVAL = 30*60*1000; //ms + + private static final int MAX_NUM_FILES = 5; + + private static final int NUM_LAUNCH_TIME_BINS = 10; + private static final int[] LAUNCH_TIME_BINS = { + 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 5000 + }; + static IUsageStats sService; private Context mContext; // structure used to maintain statistics since the last checkin. @@ -66,16 +84,48 @@ public final class UsageStatsService extends IUsageStats.Stub { // Order of locks is mFileLock followed by mStatsLock to avoid deadlocks private String mResumedPkg; private File mFile; + private String mFileLeaf; //private File mBackupFile; - private long mLastWriteRealTime; - private int _FILE_WRITE_INTERVAL = 30*60*1000; //ms - private static final String _PREFIX_DELIMIT="."; - private String mFilePrefix; + private long mLastWriteElapsedTime; + private File mDir; private Calendar mCal; - private static final int _MAX_NUM_FILES = 10; - private long mLastTime; + private int mLastWriteDay; + + static class TimeStats { + int[] times = new int[NUM_LAUNCH_TIME_BINS]; + + TimeStats() { + } + + void add(int val) { + final int[] bins = LAUNCH_TIME_BINS; + for (int i=0; i mLaunchTimes + = new HashMap(); int mLaunchCount; long mUsageTime; long mPausedTime; @@ -85,44 +135,106 @@ public final class UsageStatsService extends IUsageStats.Stub { mLaunchCount = 0; mUsageTime = 0; } + + PkgUsageStatsExtended(Parcel in) { + mLaunchCount = in.readInt(); + mUsageTime = in.readLong(); + if (localLOGV) Log.v(TAG, "Launch count: " + mLaunchCount + + ", Usage time:" + mUsageTime); + + final int N = in.readInt(); + if (localLOGV) Log.v(TAG, "Reading comps: " + N); + for (int i=0; i 0) { + for (Map.Entry ent : mLaunchTimes.entrySet()) { + out.writeString(ent.getKey()); + TimeStats times = ent.getValue(); + times.writeToParcel(out); + } + } + } + void clear() { + mLaunchTimes.clear(); mLaunchCount = 0; mUsageTime = 0; } } - UsageStatsService(String fileName) { + UsageStatsService(String dir) { mStats = new HashMap(); mStatsLock = new Object(); mFileLock = new Object(); - mFilePrefix = fileName; - mCal = Calendar.getInstance(); + mDir = new File(dir); + mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0")); + + mDir.mkdir(); + + // Remove any old usage files from previous versions. + File parentDir = mDir.getParentFile(); + String fList[] = parentDir.list(); + if (fList != null) { + String prefix = mDir.getName() + "."; + int i = fList.length; + while (i > 0) { + i--; + if (fList[i].startsWith(prefix)) { + Log.i(TAG, "Deleting old usage file: " + fList[i]); + (new File(parentDir, fList[i])).delete(); + } + } + } + // Update current stats which are binned by date - String uFileName = getCurrentDateStr(mFilePrefix); - mFile = new File(uFileName); + mFileLeaf = getCurrentDateStr(FILE_PREFIX); + mFile = new File(mDir, mFileLeaf); readStatsFromFile(); - mLastWriteRealTime = SystemClock.elapsedRealtime(); - mLastTime = new Date().getTime(); + mLastWriteElapsedTime = SystemClock.elapsedRealtime(); + // mCal was set by getCurrentDateStr(), want to use that same time. + mLastWriteDay = mCal.get(Calendar.DAY_OF_YEAR); } /* * Utility method to convert date into string. */ private String getCurrentDateStr(String prefix) { - mCal.setTime(new Date()); + mCal.setTimeInMillis(System.currentTimeMillis()); StringBuilder sb = new StringBuilder(); if (prefix != null) { sb.append(prefix); - sb.append("."); } + sb.append(mCal.get(Calendar.YEAR)); int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1; if (mm < 10) { sb.append("0"); @@ -133,7 +245,6 @@ public final class UsageStatsService extends IUsageStats.Stub { sb.append("0"); } sb.append(dd); - sb.append(mCal.get(Calendar.YEAR)); return sb.toString(); } @@ -166,11 +277,20 @@ public final class UsageStatsService extends IUsageStats.Stub { private void readStatsFLOCK(File file) throws IOException { Parcel in = getParcelForFile(file); - while (in.dataAvail() > 0) { + int vers = in.readInt(); + if (vers != VERSION) { + Log.w(TAG, "Usage stats version changed; dropping"); + return; + } + int N = in.readInt(); + while (N > 0) { + N--; String pkgName = in.readString(); - PkgUsageStatsExtended pus = new PkgUsageStatsExtended(); - pus.mLaunchCount = in.readInt(); - pus.mUsageTime = in.readLong(); + if (pkgName == null) { + break; + } + if (localLOGV) Log.v(TAG, "Reading package #" + N + ": " + pkgName); + PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in); synchronized (mStatsLock) { mStats.put(pkgName, pus); } @@ -178,27 +298,18 @@ public final class UsageStatsService extends IUsageStats.Stub { } private ArrayList getUsageStatsFileListFLOCK() { - File dir = getUsageFilesDir(); - if (dir == null) { - Log.w(TAG, "Couldnt find writable directory for usage stats file"); - return null; - } // Check if there are too many files in the system and delete older files - String fList[] = dir.list(); + String fList[] = mDir.list(); if (fList == null) { return null; } - File pre = new File(mFilePrefix); - String filePrefix = pre.getName(); - // file name followed by dot - int prefixLen = filePrefix.length()+1; ArrayList fileList = new ArrayList(); for (String file : fList) { - int index = file.indexOf(filePrefix); - if (index == -1) { + if (!file.startsWith(FILE_PREFIX)) { continue; } if (file.endsWith(".bak")) { + (new File(mDir, file)).delete(); continue; } fileList.add(file); @@ -206,20 +317,7 @@ public final class UsageStatsService extends IUsageStats.Stub { return fileList; } - private File getUsageFilesDir() { - if (mFilePrefix == null) { - return null; - } - File pre = new File(mFilePrefix); - return new File(pre.getParent()); - } - private void checkFileLimitFLOCK() { - File dir = getUsageFilesDir(); - if (dir == null) { - Log.w(TAG, "Couldnt find writable directory for usage stats file"); - return; - } // Get all usage stats output files ArrayList fileList = getUsageStatsFileListFLOCK(); if (fileList == null) { @@ -227,49 +325,54 @@ public final class UsageStatsService extends IUsageStats.Stub { return; } int count = fileList.size(); - if (count <= _MAX_NUM_FILES) { + if (count <= MAX_NUM_FILES) { return; } // Sort files Collections.sort(fileList); - count -= _MAX_NUM_FILES; + count -= MAX_NUM_FILES; // Delete older files for (int i = 0; i < count; i++) { String fileName = fileList.get(i); - File file = new File(dir, fileName); - Log.i(TAG, "Deleting file : "+fileName); + File file = new File(mDir, fileName); + Log.i(TAG, "Deleting usage file : " + fileName); file.delete(); } } - private void writeStatsToFile() { + private void writeStatsToFile(boolean force) { synchronized (mFileLock) { - long currTime = new Date().getTime(); - boolean dayChanged = ((currTime - mLastTime) >= (24*60*60*1000)); - long currRealTime = SystemClock.elapsedRealtime(); - if (((currRealTime-mLastWriteRealTime) < _FILE_WRITE_INTERVAL) && - (!dayChanged)) { - // wait till the next update - return; + mCal.setTimeInMillis(System.currentTimeMillis()); + final int curDay = mCal.get(Calendar.DAY_OF_YEAR); + // Determine if the day changed... note that this will be wrong + // if the year has changed but we are in the same day of year... + // we can probably live with this. + final boolean dayChanged = curDay != mLastWriteDay; + long currElapsedTime = SystemClock.elapsedRealtime(); + if (!force) { + if (((currElapsedTime-mLastWriteElapsedTime) < FILE_WRITE_INTERVAL) && + (!dayChanged)) { + // wait till the next update + return; + } } // Get the most recent file - String todayStr = getCurrentDateStr(mFilePrefix); + mFileLeaf = getCurrentDateStr(FILE_PREFIX); // Copy current file to back up File backupFile = new File(mFile.getPath() + ".bak"); mFile.renameTo(backupFile); try { - checkFileLimitFLOCK(); - mFile.createNewFile(); // Write mStats to file writeStatsFLOCK(); - mLastWriteRealTime = currRealTime; - mLastTime = currTime; + mLastWriteElapsedTime = currElapsedTime; if (dayChanged) { + mLastWriteDay = curDay; // clear stats synchronized (mStats) { mStats.clear(); } - mFile = new File(todayStr); + mFile = new File(mDir, mFileLeaf); + checkFileLimitFLOCK(); } // Delete the backup file if (backupFile != null) { @@ -278,6 +381,7 @@ public final class UsageStatsService extends IUsageStats.Stub { } catch (IOException e) { Log.w(TAG, "Failed writing stats to file:" + mFile); if (backupFile != null) { + mFile.delete(); backupFile.renameTo(mFile); } } @@ -286,22 +390,26 @@ public final class UsageStatsService extends IUsageStats.Stub { private void writeStatsFLOCK() throws IOException { FileOutputStream stream = new FileOutputStream(mFile); - Parcel out = Parcel.obtain(); - writeStatsToParcelFLOCK(out); - stream.write(out.marshall()); - out.recycle(); - stream.flush(); - stream.close(); + try { + Parcel out = Parcel.obtain(); + writeStatsToParcelFLOCK(out); + stream.write(out.marshall()); + out.recycle(); + stream.flush(); + } finally { + stream.close(); + } } private void writeStatsToParcelFLOCK(Parcel out) { synchronized (mStatsLock) { + out.writeInt(VERSION); Set keys = mStats.keySet(); + out.writeInt(keys.size()); for (String key : keys) { PkgUsageStatsExtended pus = mStats.get(key); out.writeString(key); - out.writeInt(pus.mLaunchCount); - out.writeLong(pus.mUsageTime); + pus.writeToParcel(out); } } } @@ -311,6 +419,11 @@ public final class UsageStatsService extends IUsageStats.Stub { ServiceManager.addService(SERVICE_NAME, asBinder()); } + public void shutdown() { + Log.w(TAG, "Writing usage stats before shutdown..."); + writeStatsToFile(true); + } + public static IUsageStats getService() { if (sService != null) { return sService; @@ -355,6 +468,10 @@ public final class UsageStatsService extends IUsageStats.Stub { return; } if (localLOGV) Log.i(TAG, "paused component:"+pkgName); + + // Persist current data to file if needed. + writeStatsToFile(false); + synchronized (mStatsLock) { PkgUsageStatsExtended pus = mStats.get(pkgName); if (pus == null) { @@ -364,8 +481,25 @@ public final class UsageStatsService extends IUsageStats.Stub { } pus.updatePause(); } - // Persist data to file - writeStatsToFile(); + } + + public void noteLaunchTime(ComponentName componentName, int millis) { + enforceCallingPermission(); + String pkgName; + if ((componentName == null) || + ((pkgName = componentName.getPackageName()) == null)) { + return; + } + + // Persist current data to file if needed. + writeStatsToFile(false); + + synchronized (mStatsLock) { + PkgUsageStatsExtended pus = mStats.get(pkgName); + if (pus != null) { + pus.addLaunchTime(componentName.getClassName(), millis); + } + } } public void enforceCallingPermission() { @@ -432,27 +566,25 @@ public final class UsageStatsService extends IUsageStats.Stub { } } - private void collectDumpInfoFLOCK(PrintWriter pw, String[] args) { + private void collectDumpInfoFLOCK(PrintWriter pw, boolean isCompactOutput, + boolean deleteAfterPrint) { List fileList = getUsageStatsFileListFLOCK(); if (fileList == null) { return; } - final boolean isCheckinRequest = scanArgs(args, "-c"); Collections.sort(fileList); - File usageFile = new File(mFilePrefix); - String dirName = usageFile.getParent(); - File dir = new File(dirName); - String filePrefix = usageFile.getName(); - // file name followed by dot - int prefixLen = filePrefix.length()+1; - String todayStr = getCurrentDateStr(null); for (String file : fileList) { - File dFile = new File(dir, file); - String dateStr = file.substring(prefixLen); + if (deleteAfterPrint && file.equalsIgnoreCase(mFileLeaf)) { + // In this mode we don't print the current day's stats, since + // they are incomplete. + continue; + } + File dFile = new File(mDir, file); + String dateStr = file.substring(FILE_PREFIX.length()); try { Parcel in = getParcelForFile(dFile); - collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCheckinRequest); - if (isCheckinRequest && !todayStr.equalsIgnoreCase(dateStr)) { + collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCompactOutput); + if (deleteAfterPrint) { // Delete old file after collecting info only for checkin requests dFile.delete(); } @@ -466,40 +598,101 @@ public final class UsageStatsService extends IUsageStats.Stub { } private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw, - String date, boolean isCheckinRequest) { - StringBuilder sb = new StringBuilder(); - sb.append("Date:"); + String date, boolean isCompactOutput) { + StringBuilder sb = new StringBuilder(512); + if (isCompactOutput) { + sb.append("D:"); + sb.append(CHECKIN_VERSION); + sb.append(','); + } else { + sb.append("Date: "); + } + sb.append(date); - boolean first = true; - while (in.dataAvail() > 0) { + + int vers = in.readInt(); + if (vers != VERSION) { + sb.append(" (old data version)"); + pw.println(sb.toString()); + return; + } + + pw.println(sb.toString()); + int N = in.readInt(); + + while (N > 0) { + N--; String pkgName = in.readString(); - int launchCount = in.readInt(); - long usageTime = in.readLong(); - if (isCheckinRequest) { - if (!first) { - sb.append(","); - } + if (pkgName == null) { + break; + } + sb.setLength(0); + PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in); + if (isCompactOutput) { + sb.append("P:"); sb.append(pkgName); sb.append(","); - sb.append(launchCount); + sb.append(pus.mLaunchCount); sb.append(","); - sb.append(usageTime); - sb.append("ms"); - } else { - if (first) { - sb.append("\n"); + sb.append(pus.mUsageTime); + sb.append('\n'); + final int NC = pus.mLaunchTimes.size(); + if (NC > 0) { + for (Map.Entry ent : pus.mLaunchTimes.entrySet()) { + sb.append("A:"); + sb.append(ent.getKey()); + TimeStats times = ent.getValue(); + for (int i=0; i 0) { + for (Map.Entry ent : pus.mLaunchTimes.entrySet()) { + sb.append(" "); + sb.append(ent.getKey()); + TimeStats times = ent.getValue(); + int lastBin = 0; + boolean first = true; + for (int i=0; i=0; i--) { final View child = getChildAt(i); - if (child != null && child.getVisibility() != GONE) { + if (child.getVisibility() != GONE) { fitRight = child.getRight(); break; } @@ -45,7 +43,7 @@ public class IconMerger extends LinearLayout { moreView = child; startIndex = i+1; } - else if (child != null && child.getVisibility() != GONE) { + else if (child.getVisibility() != GONE) { fitLeft = child.getLeft(); break; } @@ -71,7 +69,7 @@ public class IconMerger extends LinearLayout { int number = 0; for (i=startIndex; i 0) env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf)); + else + env->SetIntField(obj, gFieldIds.mBatteryStatus, + gConstants.statusUnknown); if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0) env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf)); diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java index 464085fd3cc446f51b7ca7632670cf91725f25ca..bb5f1267f2e19d79130345c444993faaf125b9fb 100644 --- a/telephony/java/android/telephony/CellLocation.java +++ b/telephony/java/android/telephony/CellLocation.java @@ -19,8 +19,14 @@ package android.telephony; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; +import android.provider.Settings; + + +import android.telephony.cdma.CdmaCellLocation; import android.telephony.gsm.GsmCellLocation; import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.RILConstants; /** * Abstract class that represents the location of the device. Currently the only @@ -56,7 +62,17 @@ public abstract class CellLocation { * @hide */ public static CellLocation newFromBundle(Bundle bundle) { - return new GsmCellLocation(bundle); + // TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0)) + // instead of SystemProperties??? + + // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup + // ITelephony have not been created + if (RILConstants.CDMA_PHONE == + SystemProperties.getInt(Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE)) { + return new CdmaCellLocation(bundle); + } else { + return new GsmCellLocation(bundle); + } } /** @@ -66,8 +82,20 @@ public abstract class CellLocation { /** * Return a new CellLocation object representing an unknown location. + * */ public static CellLocation getEmpty() { - return new GsmCellLocation(); + // TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0)) + // instead of SystemProperties??? + + // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup + // ITelephony have not been created + if (RILConstants.CDMA_PHONE == + SystemProperties.getInt(Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE)) { + return new CdmaCellLocation(); + } else { + return new GsmCellLocation(); + } } + } diff --git a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java index 0bc6c041a82a52acc87111e85b64f34c71dc40f6..8a4733941622d6bcd762b3e5af25373e44ec3560 100644 --- a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java +++ b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java @@ -25,7 +25,7 @@ import java.util.Locale; /** * Watches a {@link TextView} and if a phone number is entered will format it using - * {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on + * {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on * the current system locale when this object is created and future locale changes * may not take effect on this instance. */ @@ -35,7 +35,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { static private Locale sCachedLocale; private boolean mFormatting; private boolean mDeletingHyphen; - private int mHyphenStart; + private int mHyphenStart; private boolean mDeletingBackward; public PhoneNumberFormattingTextWatcher() { @@ -60,7 +60,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { text.delete(mHyphenStart, mHyphenStart + 1); } } - + PhoneNumberUtils.formatNumber(text, sFormatType); mFormatting = false; @@ -73,8 +73,8 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { // Make sure user is deleting one char, without a selection final int selStart = Selection.getSelectionStart(s); final int selEnd = Selection.getSelectionEnd(s); - if (s.length() > 1 // Can delete another character - && count == 1 // Deleting only one character + if (s.length() > 1 // Can delete another character + && count == 1 // Deleting only one character && after == 0 // Deleting && s.charAt(start) == '-' // a hyphen && selStart == selEnd) { // no selection @@ -89,7 +89,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { } else { mDeletingHyphen = false; } - } + } } public void onTextChanged(CharSequence s, int start, int before, int count) { diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 8a8a675e7c47ff6a008e5fefb507968f80d002c6..df6860b08365b28b15899926a693f1910c610615 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -11,18 +11,18 @@ import com.android.internal.telephony.IPhoneStateListener; /** * A listener class for monitoring changes in specific telephony states - * on the device, including service state, signal strength, message + * on the device, including service state, signal strength, message * waiting indicator (voicemail), and others. *

        - * Override the methods for the state that you wish to receive updates for, and + * Override the methods for the state that you wish to receive updates for, and * pass your PhoneStateListener object, along with bitwise-or of the LISTEN_ * flags to {@link TelephonyManager#listen TelephonyManager.listen()}. *

        * Note that access to some telephony information is - * permission-protected. Your application won't receive updates for protected - * information unless it has the appropriate permissions declared in + * permission-protected. Your application won't receive updates for protected + * information unless it has the appropriate permissions declared in * its manifest file. Where permissions apply, they are noted in the - * appropriate LISTEN_ flags. + * appropriate LISTEN_ flags. */ public class PhoneStateListener { @@ -67,17 +67,17 @@ public class PhoneStateListener { public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008; /** - * Listen for changes to the device's cell location. Note that + * Listen for changes to the device's cell location. Note that * this will result in frequent callbacks to the listener. * {@more} * Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION * ACCESS_COARSE_LOCATION} *

        - * If you need regular location updates but want more control over - * the update interval or location precision, you can set up a listener - * through the {@link android.location.LocationManager location manager} - * instead. - * + * If you need regular location updates but want more control over + * the update interval or location precision, you can set up a listener + * through the {@link android.location.LocationManager location manager} + * instead. + * * @see #onCellLocationChanged */ public static final int LISTEN_CELL_LOCATION = 0x00000010; @@ -100,7 +100,7 @@ public class PhoneStateListener { * Listen for changes to the direction of data traffic on the data * connection (cellular). * - * Example: The status bar uses this to display the appropriate + * Example: The status bar uses this to display the appropriate * data-traffic icon. * * @see #onDataActivity @@ -111,7 +111,7 @@ public class PhoneStateListener { } /** - * Callback invoked when device service state changes. + * Callback invoked when device service state changes. * * @see ServiceState#STATE_EMERGENCY_ONLY * @see ServiceState#STATE_IN_SERVICE @@ -135,28 +135,28 @@ public class PhoneStateListener { } /** - * Callback invoked when the message-waiting indicator changes. + * Callback invoked when the message-waiting indicator changes. */ public void onMessageWaitingIndicatorChanged(boolean mwi) { // default implementation empty } /** - * Callback invoked when the call-forwarding indicator changes. + * Callback invoked when the call-forwarding indicator changes. */ public void onCallForwardingIndicatorChanged(boolean cfi) { // default implementation empty } /** - * Callback invoked when device cell location changes. + * Callback invoked when device cell location changes. */ public void onCellLocationChanged(CellLocation location) { // default implementation empty } /** - * Callback invoked when device call state changes. + * Callback invoked when device call state changes. * * @see TelephonyManager#CALL_STATE_IDLE * @see TelephonyManager#CALL_STATE_RINGING @@ -167,7 +167,7 @@ public class PhoneStateListener { } /** - * Callback invoked when connection state changes. + * Callback invoked when connection state changes. * * @see TelephonyManager#DATA_DISCONNECTED * @see TelephonyManager#DATA_CONNECTING @@ -179,7 +179,7 @@ public class PhoneStateListener { } /** - * Callback invoked when data activity state changes. + * Callback invoked when data activity state changes. * * @see TelephonyManager#DATA_ACTIVITY_NONE * @see TelephonyManager#DATA_ACTIVITY_IN diff --git a/telephony/java/android/telephony/ServiceState.aidl b/telephony/java/android/telephony/ServiceState.aidl index b1cf3790ead5f9556f2ec4971d1175f09a86e07d..852288937ef0ae6639ec7154c5e5e28d41fa5f2a 100644 --- a/telephony/java/android/telephony/ServiceState.aidl +++ b/telephony/java/android/telephony/ServiceState.aidl @@ -2,16 +2,16 @@ ** ** 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 +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this 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. */ diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 2c5805178f2d7a8cdb8416014784290061153cb5..4de0954f52791742510e4e5469ecbe5bdf44c71e 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -19,7 +19,7 @@ package android.telephony; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.telephony.Phone; +import android.util.Log; /** * Contains phone state and service related information. @@ -35,6 +35,8 @@ import com.android.internal.telephony.Phone; */ public class ServiceState implements Parcelable { + static final String LOG_TAG = "PHONE"; + /** * Normal operation condition, the phone is registered * with an operator either in home network or in roaming. @@ -59,13 +61,61 @@ public class ServiceState implements Parcelable { */ public static final int STATE_POWER_OFF = 3; + + /** + * Available radio technologies for GSM, UMTS and CDMA. + */ + /** @hide */ + public static final int RADIO_TECHNOLOGY_UNKNOWN = 0; + /** @hide */ + public static final int RADIO_TECHNOLOGY_GPRS = 1; + /** @hide */ + public static final int RADIO_TECHNOLOGY_EDGE = 2; + /** @hide */ + public static final int RADIO_TECHNOLOGY_UMTS = 3; + /** @hide */ + public static final int RADIO_TECHNOLOGY_IS95A = 4; + /** @hide */ + public static final int RADIO_TECHNOLOGY_IS95B = 5; + /** @hide */ + public static final int RADIO_TECHNOLOGY_1xRTT = 6; + /** @hide */ + public static final int RADIO_TECHNOLOGY_EVDO_0 = 7; + /** @hide */ + public static final int RADIO_TECHNOLOGY_EVDO_A = 8; + + /** + * Available registration states for GSM, UMTS and CDMA. + */ + /** @hide */ + public static final int REGISTRATION_STATE_NOT_REGISTERED_AND_NOT_SEARCHING = 0; + /** @hide */ + public static final int REGISTRATION_STATE_HOME_NETWORK = 1; + /** @hide */ + public static final int REGISTRATION_STATE_NOT_REGISTERED_AND_SEARCHING = 2; + /** @hide */ + public static final int REGISTRATION_STATE_REGISTRATION_DENIED = 3; + /** @hide */ + public static final int REGISTRATION_STATE_UNKNOWN = 4; + /** @hide */ + public static final int REGISTRATION_STATE_ROAMING = 5; + /** @hide */ + public static final int REGISTRATION_STATE_ROAMING_AFFILIATE = 6; + private int mState = STATE_OUT_OF_SERVICE; private boolean mRoaming; + private int mExtendedCdmaRoaming; private String mOperatorAlphaLong; private String mOperatorAlphaShort; private String mOperatorNumeric; private boolean mIsManualNetworkSelection; + //***** CDMA + private int mRadioTechnology; + private boolean mCssIndicator; + private int mNetworkId; + private int mSystemId; + /** * Create a new ServiceState from a intent notifier Bundle * @@ -105,6 +155,11 @@ public class ServiceState implements Parcelable { mOperatorAlphaShort = s.mOperatorAlphaShort; mOperatorNumeric = s.mOperatorNumeric; mIsManualNetworkSelection = s.mIsManualNetworkSelection; + mRadioTechnology = s.mRadioTechnology; + mCssIndicator = s.mCssIndicator; + mNetworkId = s.mNetworkId; + mSystemId = s.mSystemId; + mExtendedCdmaRoaming = s.mExtendedCdmaRoaming; } /** @@ -117,6 +172,11 @@ public class ServiceState implements Parcelable { mOperatorAlphaShort = in.readString(); mOperatorNumeric = in.readString(); mIsManualNetworkSelection = in.readInt() != 0; + mRadioTechnology = in.readInt(); + mCssIndicator = (in.readInt() != 0); + mNetworkId = in.readInt(); + mSystemId = in.readInt(); + mExtendedCdmaRoaming = in.readInt(); } public void writeToParcel(Parcel out, int flags) { @@ -126,6 +186,11 @@ public class ServiceState implements Parcelable { out.writeString(mOperatorAlphaShort); out.writeString(mOperatorNumeric); out.writeInt(mIsManualNetworkSelection ? 1 : 0); + out.writeInt(mRadioTechnology); + out.writeInt(mCssIndicator ? 1 : 0); + out.writeInt(mNetworkId); + out.writeInt(mSystemId); + out.writeInt(mExtendedCdmaRoaming); } public int describeContents() { @@ -166,6 +231,11 @@ public class ServiceState implements Parcelable { return mRoaming; } + /** @hide */ + public int getExtendedCdmaRoaming(){ + return this.mExtendedCdmaRoaming; + } + /** * Get current registered operator name in long alphanumeric format * @@ -213,18 +283,19 @@ public class ServiceState implements Parcelable { @Override public int hashCode() { - return (mState * 0x1234) + return ((mState * 0x1234) + (mRoaming ? 1 : 0) + (mIsManualNetworkSelection ? 1 : 0) + ((null == mOperatorAlphaLong) ? 0 : mOperatorAlphaLong.hashCode()) + ((null == mOperatorAlphaShort) ? 0 : mOperatorAlphaShort.hashCode()) - + ((null == mOperatorNumeric) ? 0 : mOperatorNumeric.hashCode()); + + ((null == mOperatorNumeric) ? 0 : mOperatorNumeric.hashCode()) + + (mExtendedCdmaRoaming)); } @Override public boolean equals (Object o) { ServiceState s; - + try { s = (ServiceState) o; } catch (ClassCastException ex) { @@ -235,21 +306,66 @@ public class ServiceState implements Parcelable { return false; } - return mState == s.mState + return (mState == s.mState && mRoaming == s.mRoaming && mIsManualNetworkSelection == s.mIsManualNetworkSelection && equalsHandlesNulls(mOperatorAlphaLong, s.mOperatorAlphaLong) && equalsHandlesNulls(mOperatorAlphaShort, s.mOperatorAlphaShort) - && equalsHandlesNulls(mOperatorNumeric, s.mOperatorNumeric); + && equalsHandlesNulls(mOperatorNumeric, s.mOperatorNumeric) + && equalsHandlesNulls(mRadioTechnology, s.mRadioTechnology) + && equalsHandlesNulls(mCssIndicator, s.mCssIndicator) + && equalsHandlesNulls(mNetworkId, s.mNetworkId) + && equalsHandlesNulls(mSystemId, s.mSystemId) + && equalsHandlesNulls(mExtendedCdmaRoaming, s.mExtendedCdmaRoaming)); } @Override public String toString() { - return mState + " " + (mRoaming ? "roaming" : "home") + String radioTechnology = new String("Error in radioTechnology"); + + switch(this.mRadioTechnology) { + case 0: + radioTechnology = "Unknown"; + break; + case 1: + radioTechnology = "GPRS"; + break; + case 2: + radioTechnology = "EDGE"; + break; + case 3: + radioTechnology = "UMTS"; + break; + case 4: + radioTechnology = "IS95A"; + break; + case 5: + radioTechnology = "IS95B"; + break; + case 6: + radioTechnology = "1xRTT"; + break; + case 7: + radioTechnology = "EvDo rev. 0"; + break; + case 8: + radioTechnology = "EvDo rev. A"; + break; + default: + Log.w(LOG_TAG, "mRadioTechnology variable out of range."); + break; + } + + return (mState + " " + (mRoaming ? "roaming" : "home") + " " + mOperatorAlphaLong + " " + mOperatorAlphaShort + " " + mOperatorNumeric - + " " + (mIsManualNetworkSelection ? "(manual)" : ""); + + " " + (mIsManualNetworkSelection ? "(manual)" : "") + + " " + radioTechnology + + " " + (mCssIndicator ? "CSS supported" : "CSS not supported") + + "NetworkId: " + mNetworkId + + "SystemId: " + mSystemId + + "ExtendedCdmaRoaming: " + mExtendedCdmaRoaming); } public void setStateOutOfService() { @@ -259,6 +375,11 @@ public class ServiceState implements Parcelable { mOperatorAlphaShort = null; mOperatorNumeric = null; mIsManualNetworkSelection = false; + mRadioTechnology = 0; + mCssIndicator = false; + mNetworkId = -1; + mSystemId = -1; + mExtendedCdmaRoaming = -1; } public void setStateOff() { @@ -268,6 +389,11 @@ public class ServiceState implements Parcelable { mOperatorAlphaShort = null; mOperatorNumeric = null; mIsManualNetworkSelection = false; + mRadioTechnology = 0; + mCssIndicator = false; + mNetworkId = -1; + mSystemId = -1; + mExtendedCdmaRoaming = -1; } public void setState(int state) { @@ -278,6 +404,11 @@ public class ServiceState implements Parcelable { mRoaming = roaming; } + /** @hide */ + public void setExtendedCdmaRoaming (int roaming) { + this.mExtendedCdmaRoaming = roaming; + } + public void setOperatorName(String longName, String shortName, String numeric) { mOperatorAlphaLong = longName; mOperatorAlphaShort = shortName; @@ -287,7 +418,7 @@ public class ServiceState implements Parcelable { public void setIsManualSelection(boolean isManual) { mIsManualNetworkSelection = isManual; } - + /** * Test whether two objects hold the same data values or both are null * @@ -312,6 +443,11 @@ public class ServiceState implements Parcelable { mOperatorAlphaShort = m.getString("operator-alpha-short"); mOperatorNumeric = m.getString("operator-numeric"); mIsManualNetworkSelection = m.getBoolean("manual"); + mRadioTechnology = m.getInt("radioTechnology"); + mCssIndicator = m.getBoolean("cssIndicator"); + mNetworkId = m.getInt("networkId"); + mSystemId = m.getInt("systemId"); + mExtendedCdmaRoaming = m.getInt("extendedCdmaRoaming"); } /** @@ -327,5 +463,47 @@ public class ServiceState implements Parcelable { m.putString("operator-alpha-short", mOperatorAlphaShort); m.putString("operator-numeric", mOperatorNumeric); m.putBoolean("manual", Boolean.valueOf(mIsManualNetworkSelection)); + m.putInt("radioTechnology", mRadioTechnology); + m.putBoolean("cssIndicator", mCssIndicator); + m.putInt("networkId", mNetworkId); + m.putInt("systemId", mSystemId); + m.putInt("extendedCdmaRoaming", mExtendedCdmaRoaming); + } + + //***** CDMA + /** @hide */ + public void setRadioTechnology(int state) { + this.mRadioTechnology = state; + } + + /** @hide */ + public void setCssIndicator(int css) { + this.mCssIndicator = (css != 0); + } + + /** @hide */ + public void setSystemAndNetworkId(int systemId, int networkId) { + this.mSystemId = systemId; + this.mNetworkId = networkId; + } + + /** @hide */ + public int getRadioTechnology() { + return this.mRadioTechnology; + } + + /** @hide */ + public int getCssIndicator() { + return this.mCssIndicator ? 1 : 0; + } + + /** @hide */ + public int getNetworkId() { + return this.mNetworkId; + } + + /** @hide */ + public int getSystemId() { + return this.mSystemId; } } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java new file mode 100644 index 0000000000000000000000000000000000000000..9395d662506407c285097ef9681507b531990bff --- /dev/null +++ b/telephony/java/android/telephony/SmsManager.java @@ -0,0 +1,441 @@ +/* + * 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.telephony; + +import android.app.PendingIntent; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.TextUtils; + +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.ISms; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.SmsRawData; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_8BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.ENCODING_UNKNOWN; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; + +/** + * Manages SMS operations such as sending data, text, and pdu SMS messages. + * Get this object by calling the static method SmsManager.getDefault(). + * @hide + */ +public final class SmsManager { + private static SmsManager sInstance; + + /** + * Send a text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or text are empty + */ + public void sendTextMessage( + String destinationAddress, String scAddress, String text, + PendingIntent sentIntent, PendingIntent deliveryIntent) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + + if (TextUtils.isEmpty(text)) { + throw new IllegalArgumentException("Invalid message body"); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( + scAddress, destinationAddress, text, (deliveryIntent != null)); + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + + /** + * Divide a text message into several messages, none bigger than + * the maximum SMS message size. + * + * @param text the original message. Must not be null. + * @return an ArrayList of strings that, in order, + * comprise the original message + */ + public ArrayList divideMessage(String text) { + int size = text.length(); + int[] params = SmsMessage.calculateLength(text, false); + /* SmsMessage.calculateLength returns an int[4] with: + * int[0] being the number of SMS's required, + * int[1] the number of code units used, + * int[2] is the number of code units remaining until the next message. + * int[3] is the encoding type that should be used for the message. + */ + int messageCount = params[0]; + int encodingType = params[3]; + ArrayList result = new ArrayList(messageCount); + + int start = 0; + int limit; + + if (messageCount > 1) { + limit = (encodingType == ENCODING_7BIT)? + MAX_USER_DATA_SEPTETS_WITH_HEADER: MAX_USER_DATA_BYTES_WITH_HEADER; + } else { + limit = (encodingType == ENCODING_7BIT)? + MAX_USER_DATA_SEPTETS: MAX_USER_DATA_BYTES; + } + + try { + while (start < size) { + int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType); + result.add(text.substring(start, end)); + start = end; + } + } + catch (EncodeException e) { + // ignore it. + } + return result; + } + + /** + * Send a multi-part text based SMS. The callee should have already + * divided the message into correctly sized parts by calling + * divideMessage. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an ArrayList of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applicaitons, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + */ + public void sendMultipartTextMessage( + String destinationAddress, String scAddress, ArrayList parts, + ArrayList sentIntents, ArrayList deliveryIntents) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + if (parts == null || parts.size() < 1) { + throw new IllegalArgumentException("Invalid message body"); + } + + if (parts.size() > 1) { + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + iccISms.sendMultipartText(destinationAddress, scAddress, parts, + sentIntents, deliveryIntents); + } + } catch (RemoteException ex) { + // ignore it + } + } else { + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + if (sentIntents != null && sentIntents.size() > 0) { + sentIntent = sentIntents.get(0); + } + if (deliveryIntents != null && deliveryIntents.size() > 0) { + deliveryIntent = deliveryIntents.get(0); + } + sendTextMessage(destinationAddress, scAddress, parts.get(0), + sentIntent, deliveryIntent); + } + } + + /** + * Send a data based SMS to a specific application port. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param destinationPort the port to deliver the message to + * @param data the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applicaitons, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + */ + public void sendDataMessage( + String destinationAddress, String scAddress, short destinationPort, + byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + + if (data == null || data.length == 0) { + throw new IllegalArgumentException("Invalid message data"); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( + scAddress, destinationAddress, + destinationPort, data, (deliveryIntent != null)); + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + + /** + * Send a raw SMS PDU. + * + * @param smsc the SMSC to send the message through, or NULL for the + * default SMSC + * @param pdu the raw PDU to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is successfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @hide + */ + private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + iccISms.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + } catch (RemoteException ex) { + // ignore it + } + } + + /** + * Get the default instance of the SmsManager + * + * @return the default instance of the SmsManager + */ + public static SmsManager getDefault() { + if (sInstance == null) { + sInstance = new SmsManager(); + } + return sInstance; + } + + private SmsManager() { + //nothing + } + + /** + * Copy a raw SMS PDU to the ICC. + * + * @param smsc the SMSC for this message, or NULL for the default SMSC + * @param pdu the raw PDU to store + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) + * @return true for success + * + * {@hide} + */ + public boolean copyMessageToIcc(byte[] smsc, byte[] pdu, int status) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.copyMessageToIccEf(status, pdu, smsc); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Delete the specified message from the ICC. + * + * @param messageIndex is the record index of the message on ICC + * @return true for success + * + * {@hide} + */ + public boolean + deleteMessageFromIcc(int messageIndex) { + boolean success = false; + byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1]; + Arrays.fill(pdu, (byte)0xff); + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.updateMessageOnIccEf(messageIndex, STATUS_ON_ICC_FREE, pdu); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Update the specified message on the ICC. + * + * @param messageIndex record index of message to update + * @param newStatus new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) + * @param pdu the raw PDU to store + * @return true for success + * + * {@hide} + */ + public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.updateMessageOnIccEf(messageIndex, newStatus, pdu); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Retrieves all messages currently stored on ICC. + * + * @return ArrayList of SmsMessage objects + * + * {@hide} + */ + public ArrayList getAllMessagesFromIcc() { + List records = null; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + records = iccISms.getAllMessagesFromIccEf(); + } + } catch (RemoteException ex) { + // ignore it + } + + return createMessageListFromRawRecords(records); + } + + /** + * Create a list of SmsMessages from a list of RawSmsData + * records returned by getAllMessagesFromIcc() + * + * @param records SMS EF records, returned by + * getAllMessagesFromIcc + * @return ArrayList of SmsMessage objects. + */ + private ArrayList createMessageListFromRawRecords(List records) { + ArrayList messages = new ArrayList(); + if (records != null) { + int count = records.size(); + for (int i = 0; i < count; i++) { + SmsRawData data = (SmsRawData)records.get(i); + // List contains all records, including "free" records (null) + if (data != null) { + SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); + messages.add(sms); + } + } + } + return messages; + } + + // see SmsMessage.getStatusOnIcc + + /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_FREE = 0; + + /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_READ = 1; + + /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_UNREAD = 3; + + /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_SENT = 5; + + /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_UNSENT = 7; + + // SMS send failure result codes + + /** Generic failure cause */ + static public final int RESULT_ERROR_GENERIC_FAILURE = 1; + /** Failed because radio was explicitly turned off */ + static public final int RESULT_ERROR_RADIO_OFF = 2; + /** Failed because no pdu provided */ + static public final int RESULT_ERROR_NULL_PDU = 3; + /** Failed because service is currently unavailable */ + static public final int RESULT_ERROR_NO_SERVICE = 4; +} diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..3b7f4b522314e726eefd91305747a38484e7578d --- /dev/null +++ b/telephony/java/android/telephony/SmsMessage.java @@ -0,0 +1,628 @@ +/* + * 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.telephony; + +import android.os.Parcel; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; + +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; + + +/** + * A Short Message Service message. + * @hide + */ +public class SmsMessage { + private static final boolean LOCAL_DEBUG = true; + private static final String LOG_TAG = "SMS"; + + /** + * SMS Class enumeration. + * See TS 23.038. + * + */ + public enum MessageClass{ + UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; + } + + /** Unknown encoding scheme (see TS 23.038) */ + public static final int ENCODING_UNKNOWN = 0; + /** 7-bit encoding scheme (see TS 23.038) */ + public static final int ENCODING_7BIT = 1; + /** 8-bit encoding scheme (see TS 23.038) */ + public static final int ENCODING_8BIT = 2; + /** 16-bit encoding scheme (see TS 23.038) */ + public static final int ENCODING_16BIT = 3; + + /** The maximum number of payload bytes per message */ + public static final int MAX_USER_DATA_BYTES = 140; + + /** + * The maximum number of payload bytes per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + * + * @hide pending API Council approval to extend the public API + */ + public 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; + + /** + * The maximum number of payload septets per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + */ + public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; + + /** Contains actual SmsMessage. Only public for debugging and for framework layer. + * {@hide} + */ + public SmsMessageBase mWrappedSmsMessage; + + public static class SubmitPdu extends SubmitPduBase { + + //Constructor + public SubmitPdu() { + } + + /* {@hide} */ + protected SubmitPdu(SubmitPduBase spb) { + this.encodedMessage = spb.encodedMessage; + this.encodedScAddress = spb.encodedScAddress; + } + + } + + // Constructor + public SmsMessage() { + this(getSmsFacility()); + } + + private SmsMessage(SmsMessageBase smb) { + mWrappedSmsMessage = smb; + } + + /** + * Create an SmsMessage from a raw PDU. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); + } + + return new SmsMessage(wrappedMessage); + } + + /** + * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the + * +CMT unsolicited response (PDU mode, of course) + * +CMT: [<alpha>], + * + * Only public for debugging and for RIL + * + * {@hide} + */ + public static SmsMessage newFromCMT(String[] lines){ + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); + } + + return new SmsMessage(wrappedMessage); + } + + /** @hide */ + protected static SmsMessage newFromCMTI(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line); + } + + return new SmsMessage(wrappedMessage); + } + + /** @hide */ + public static SmsMessage newFromCDS(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line); + } + + return new SmsMessage(wrappedMessage); + } + + /** @hide */ + public static SmsMessage newFromParcel(Parcel p) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p); + } + + return new SmsMessage(wrappedMessage); + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by SmsManager.getAllMessagesFromSim + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( + index, data); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( + index, data); + } + + return new SmsMessage(wrappedMessage); + } + + /** + * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the + * length in bytes (not hex chars) less the SMSC header + */ + public static int getTPLayerLengthForPDU(String pdu) { + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu); + } else { + return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu); + } + } + + /** + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message, given the + * current encoding. + * + * @param messageBody the message to encode + * @param use7bitOnly if true, characters that are not part of the GSM + * alphabet are counted as a single space char. If false, a + * messageBody containing non-GSM alphabet characters is calculated + * for 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's required, int[1] + * the number of code units used, and int[2] is the number of code + * units remaining until the next message. int[3] is the encoding + * type that should be used for the message. + */ + public static int[] calculateLength(CharSequence messageBody, boolean use7bitOnly) { + int ret[] = new int[4]; + + try { + // Try GSM alphabet + int septets = GsmAlphabet.countGsmSeptets(messageBody, !use7bitOnly); + ret[1] = septets; + if (septets > MAX_USER_DATA_SEPTETS) { + ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1; + 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 UCS-2 + int octets = messageBody.length() * 2; + 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] = (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)/2; + } + ret[3] = ENCODING_16BIT; + } + + return ret; + } + + /** + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message, given the + * current encoding. + * + * @param messageBody the message to encode + * @param use7bitOnly if true, characters that are not part of the GSM + * alphabet are counted as a single space char. If false, a + * messageBody containing non-GSM alphabet characters is calculated + * for 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's required, int[1] + * the number of code units used, and int[2] is the number of code + * units remaining until the next message. int[3] is the encoding + * type that should be used for the message. + */ + public static int[] calculateLength(String messageBody, boolean use7bitOnly) { + return calculateLength((CharSequence)messageBody, use7bitOnly); + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] header) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); + } + + return new SubmitPdu(spb); + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param destinationPort the port to deliver the message to at the + * destination + * @param data the dat for the message + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Returns the address of the SMS service center that relayed this message + * or null if there is none. + */ + public String getServiceCenterAddress() { + return mWrappedSmsMessage.getServiceCenterAddress(); + } + + /** + * Returns the originating address (sender) of this SMS message in String + * form or null if unavailable + */ + public String getOriginatingAddress() { + return mWrappedSmsMessage.getOriginatingAddress(); + } + + /** + * Returns the originating address, or email from address if this message + * was from an email gateway. Returns null if originating address + * unavailable. + */ + public String getDisplayOriginatingAddress() { + return mWrappedSmsMessage.getDisplayOriginatingAddress(); + } + + /** + * Returns the message body as a String, if it exists and is text based. + * @return message body is there is one, otherwise null + */ + public String getMessageBody() { + return mWrappedSmsMessage.getMessageBody(); + } + + /** + * Returns the class of this message. + */ + public MessageClass getMessageClass() { + return mWrappedSmsMessage.getMessageClass(); + } + + /** + * Returns the message body, or email message body if this message was from + * an email gateway. Returns null if message body unavailable. + */ + public String getDisplayMessageBody() { + return mWrappedSmsMessage.getDisplayMessageBody(); + } + + /** + * Unofficial convention of a subject line enclosed in parens empty string + * if not present + */ + public String getPseudoSubject() { + return mWrappedSmsMessage.getPseudoSubject(); + } + + /** + * Returns the service centre timestamp in currentTimeMillis() format + */ + public long getTimestampMillis() { + return mWrappedSmsMessage.getTimestampMillis(); + } + + /** + * Returns true if message is an email. + * + * @return true if this message came through an email gateway and email + * sender / subject / parsed body are available + */ + public boolean isEmail() { + return mWrappedSmsMessage.isEmail(); + } + + /** + * @return if isEmail() is true, body of the email sent through the gateway. + * null otherwise + */ + public String getEmailBody() { + return mWrappedSmsMessage.getEmailBody(); + } + + /** + * @return if isEmail() is true, email from address of email sent through + * the gateway. null otherwise + */ + public String getEmailFrom() { + return mWrappedSmsMessage.getEmailFrom(); + } + + /** + * Get protocol identifier. + */ + public int getProtocolIdentifier() { + return mWrappedSmsMessage.getProtocolIdentifier(); + } + + /** + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" + * SMS + */ + public boolean isReplace() { + return mWrappedSmsMessage.isReplace(); + } + + /** + * Returns true for CPHS MWI toggle message. + * + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section + * B.4.2 + */ + public boolean isCphsMwiMessage() { + return mWrappedSmsMessage.isCphsMwiMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) clear message + */ + public boolean isMWIClearMessage() { + return mWrappedSmsMessage.isMWIClearMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) set message + */ + public boolean isMWISetMessage() { + return mWrappedSmsMessage.isMWISetMessage(); + } + + /** + * returns true if this message is a "Message Waiting Indication Group: + * Discard Message" notification and should not be stored. + */ + public boolean isMwiDontStore() { + return mWrappedSmsMessage.isMwiDontStore(); + } + + /** + * returns the user data section minus the user data header if one was + * present. + */ + public byte[] getUserData() { + return mWrappedSmsMessage.getUserData(); + } + + /* Not part of the SDK interface and only needed by specific classes: + protected SmsHeader getUserDataHeader() + */ + + /** + * Returns the raw PDU for the message. + * + * @return the raw PDU for the message. + */ + public byte[] getPdu() { + return mWrappedSmsMessage.getPdu(); + } + + /** + * Returns the status of the message on the SIM (read, unread, sent, unsent). + * + * @return the status of the message on the SIM. These are: + * SmsManager.STATUS_ON_SIM_FREE + * SmsManager.STATUS_ON_SIM_READ + * SmsManager.STATUS_ON_SIM_UNREAD + * SmsManager.STATUS_ON_SIM_SEND + * SmsManager.STATUS_ON_SIM_UNSENT + * @deprecated Use getStatusOnIcc instead. + */ + @Deprecated public int getStatusOnSim() { + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + */ + public int getStatusOnIcc() { + + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the record index of the message on the SIM (1-based index). + * @return the record index of the message on the SIM, or -1 if this + * SmsMessage was not created from a SIM SMS EF record. + * @deprecated Use getIndexOnIcc instead. + */ + @Deprecated public int getIndexOnSim() { + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + */ + public int getIndexOnIcc() { + + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * GSM: + * For an SMS-STATUS-REPORT message, this returns the status field from + * the status report. This field indicates the status of a previously + * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a + * description of values. + * CDMA: + * For not interfering with status codes from GSM, the value is + * shifted to the bits 31-16. + * The value is composed of an error class (bits 25-24) and a status code (bits 23-16). + * Possible codes are described in C.S0015-B, v2.0, 4.5.21. + * + * @return 0 indicates the previously sent message was received. + * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 + * for a description of other possible values. + */ + public int getStatus() { + return mWrappedSmsMessage.getStatus(); + } + + /** + * Return true iff the message is a SMS-STATUS-REPORT message. + */ + public boolean isStatusReportMessage() { + return mWrappedSmsMessage.isStatusReportMessage(); + } + + /** + * Returns true iff the TP-Reply-Path bit is set in + * this message. + */ + public boolean isReplyPathPresent() { + return mWrappedSmsMessage.isReplyPathPresent(); + } + + /** This method returns the reference to a specific + * SmsMessage object, which is used for accessing its static methods. + * @return Specific SmsMessage. + */ + private static final SmsMessageBase getSmsFacility(){ + int activePhone = TelephonyManager.getDefault().getPhoneType(); + if (PHONE_TYPE_CDMA == activePhone) { + return new com.android.internal.telephony.cdma.SmsMessage(); + } else { + return new com.android.internal.telephony.gsm.SmsMessage(); + } + } +} diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index c7166ce875660fbd31e9c64d5e3477d9ca3e1a0e..559542a474c7cf11dbb3cd5f3f5f3940f0a90ec0 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -28,25 +28,31 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; +import android.telephony.CellLocation; +import com.android.internal.telephony.IPhoneSubInfo; +import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.ITelephonyRegistry; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.TelephonyProperties; /** * Provides access to information about the telephony services on * the device. Applications can use the methods in this class to * determine telephony services and states, as well as to access some - * types of subscriber information. Applications can also register - * a listener to receive notification of telephony state changes. + * types of subscriber information. Applications can also register + * a listener to receive notification of telephony state changes. *

        * You do not instantiate this class directly; instead, you retrieve - * a reference to an instance through + * a reference to an instance through * {@link android.content.Context#getSystemService * Context.getSystemService(Context.TELEPHONY_SERVICE)}. *

        * Note that acess to some telephony information is - * permission-protected. Your application cannot access the protected - * information unless it has the appropriate permissions declared in - * its manifest file. Where permissions apply, they are noted in the - * the methods through which you access the protected information. + * permission-protected. Your application cannot access the protected + * information unless it has the appropriate permissions declared in + * its manifest file. Where permissions apply, they are noted in the + * the methods through which you access the protected information. */ public class TelephonyManager { private static final String TAG = "TelephonyManager"; @@ -154,10 +160,10 @@ public class TelephonyManager { // /** - * Returns the software version number for the device, for example, + * Returns the software version number for the device, for example, * the IMEI/SV for GSM phones. * - *

        Requires Permission: + *

        Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceSoftwareVersion() { @@ -169,10 +175,10 @@ public class TelephonyManager { } /** - * Returns the unique device ID, for example,the IMEI for GSM + * Returns the unique device ID, for example, the IMEI for GSM and the MEID for CDMA * phones. * - *

        Requires Permission: + *

        Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceId() { @@ -202,7 +208,7 @@ public class TelephonyManager { * Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged * PhoneStateListener.onCellLocationChanged} will be called on location updates. * - *

        Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES + *

        Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES * CONTROL_LOCATION_UPDATES} * * @hide @@ -258,23 +264,37 @@ public class TelephonyManager { public static final int PHONE_TYPE_GSM = 1; /** - * Returns a constant indicating the device phone type. - * + * CDMA phone + * @hide + */ + public static final int PHONE_TYPE_CDMA = 2; + + /** + * Returns a constant indicating the device phone type. + * * @see #PHONE_TYPE_NONE * @see #PHONE_TYPE_GSM + * @see #PHONE_TYPE_CDMA */ public int getPhoneType() { - // in the future, we should really check this - return PHONE_TYPE_GSM; + try{ + if(getITelephony().getActivePhoneType() == RILConstants.CDMA_PHONE) { + return PHONE_TYPE_CDMA; + } else { + return PHONE_TYPE_GSM; + } + }catch(RemoteException ex){ + return PHONE_TYPE_NONE; + } } // - // + // // Current Network // // - /** + /** * Returns the alphabetic name of current registered operator. *

        * Availability: Only when user is registered to a network @@ -283,7 +303,7 @@ public class TelephonyManager { return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA); } - /** + /** * Returns the numeric name (MCC+MNC) of current registered operator. *

        * Availability: Only when user is registered to a network @@ -292,7 +312,7 @@ public class TelephonyManager { return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC); } - /** + /** * Returns true if the device is considered roaming on the current * network, for GSM purposes. *

        @@ -302,7 +322,7 @@ public class TelephonyManager { return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING)); } - /** + /** * Returns the ISO country code equivilent of the current registered * operator's MCC (Mobile Country Code). *

        @@ -320,9 +340,20 @@ public class TelephonyManager { public static final int NETWORK_TYPE_EDGE = 2; /** Current network is UMTS */ public static final int NETWORK_TYPE_UMTS = 3; + /** Current network is CDMA: Either IS95A or IS95B*/ + /** @hide */ + public static final int NETWORK_TYPE_CDMA = 4; + /** Current network is EVDO revision 0 or revision A*/ + /** @hide */ + public static final int NETWORK_TYPE_EVDO_0 = 5; + /** @hide */ + public static final int NETWORK_TYPE_EVDO_A = 6; + /** Current network is 1xRTT*/ + /** @hide */ + public static final int NETWORK_TYPE_1xRTT = 7; /** - * Returns a constant indicating the radio technology (network type) + * Returns a constant indicating the radio technology (network type) * currently in use on the device. * @return the network type * @@ -330,6 +361,10 @@ public class TelephonyManager { * @see #NETWORK_TYPE_GPRS * @see #NETWORK_TYPE_EDGE * @see #NETWORK_TYPE_UMTS + * @see #NETWORK_TYPE_CDMA + * @see #NETWORK_TYPE_EVDO_0 + * @see #NETWORK_TYPE_EVDO_A + * @see #NETWORK_TYPE_1xRTT */ public int getNetworkType() { String prop = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE); @@ -342,6 +377,18 @@ public class TelephonyManager { else if ("UMTS".equals(prop)) { return NETWORK_TYPE_UMTS; } + else if ("CDMA".equals(prop)) { + return NETWORK_TYPE_CDMA; + } + else if ("CDMA - EvDo rev. 0".equals(prop)) { + return NETWORK_TYPE_EVDO_0; + } + else if ("CDMA - EvDo rev. A".equals(prop)) { + return NETWORK_TYPE_EVDO_A; + } + else if ("CDMA - 1xRTT".equals(prop)) { + return NETWORK_TYPE_1xRTT; + } else { return NETWORK_TYPE_UNKNOWN; } @@ -362,6 +409,14 @@ public class TelephonyManager { return "EDGE"; case NETWORK_TYPE_UMTS: return "UMTS"; + case NETWORK_TYPE_CDMA: + return "CDMA"; + case NETWORK_TYPE_EVDO_0: + return "CDMA - EvDo rev. 0"; + case NETWORK_TYPE_EVDO_A: + return "CDMA - EvDo rev. A"; + case NETWORK_TYPE_1xRTT: + return "CDMA - 1xRTT"; default: return "UNKNOWN"; } @@ -375,7 +430,7 @@ public class TelephonyManager { /** SIM card state: Unknown. Signifies that the SIM is in transition * between states. For example, when the user inputs the SIM pin - * under PIN_REQUIRED state, a query for sim status returns + * under PIN_REQUIRED state, a query for sim status returns * this state before turning to SIM_STATE_READY. */ public static final int SIM_STATE_UNKNOWN = 0; /** SIM card state: no SIM card is available in the device */ @@ -388,11 +443,11 @@ public class TelephonyManager { public static final int SIM_STATE_NETWORK_LOCKED = 4; /** SIM card state: Ready */ public static final int SIM_STATE_READY = 5; - - /** - * Returns a constant indicating the state of the + + /** + * Returns a constant indicating the state of the * device SIM card. - * + * * @see #SIM_STATE_UNKNOWN * @see #SIM_STATE_ABSENT * @see #SIM_STATE_PIN_REQUIRED @@ -422,7 +477,7 @@ public class TelephonyManager { } } - /** + /** * Returns the MCC+MNC (mobile country code + mobile network code) of the * provider of the SIM. 5 or 6 decimal digits. *

        @@ -431,36 +486,36 @@ public class TelephonyManager { * @see #getSimState */ public String getSimOperator() { - return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC); + return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC); } - /** - * Returns the Service Provider Name (SPN). + /** + * Returns the Service Provider Name (SPN). *

        * Availability: SIM state must be {@link #SIM_STATE_READY} * * @see #getSimState */ public String getSimOperatorName() { - return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA); + return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA); } - /** + /** * Returns the ISO country code equivalent for the SIM provider's country code. */ public String getSimCountryIso() { - return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ISO_COUNTRY); + return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY); } /** * Returns the serial number of the SIM, if applicable. *

        - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSimSerialNumber() { try { - return getSubscriberInfo().getSimSerialNumber(); + return getSubscriberInfo().getIccSerialNumber(); } catch (RemoteException ex) { } return null; @@ -475,7 +530,7 @@ public class TelephonyManager { /** * Returns the unique subscriber ID, for example, the IMSI for a GSM phone. *

        - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSubscriberId() { @@ -487,10 +542,10 @@ public class TelephonyManager { } /** - * Returns the phone number string for line 1, for example, the MSISDN + * Returns the phone number string for line 1, for example, the MSISDN * for a GSM phone. *

        - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getLine1Number() { @@ -502,9 +557,9 @@ public class TelephonyManager { } /** - * Returns the alphabetic identifier associated with the line 1 number. + * Returns the alphabetic identifier associated with the line 1 number. *

        - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * @hide * nobody seems to call this. @@ -520,7 +575,7 @@ public class TelephonyManager { /** * Returns the voice mail number. *

        - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailNumber() { @@ -535,7 +590,7 @@ public class TelephonyManager { * Retrieves the alphabetic identifier associated with the voice * mail number. *

        - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailAlphaTag() { @@ -555,10 +610,10 @@ public class TelephonyManager { /** Device call state: No activity. */ public static final int CALL_STATE_IDLE = 0; /** Device call state: Ringing. A new call arrived and is - * ringing or waiting. In the latter case, another call is + * ringing or waiting. In the latter case, another call is * already active. */ public static final int CALL_STATE_RINGING = 1; - /** Device call state: Off-hook. At least one call exists + /** Device call state: Off-hook. At least one call exists * that is dialing, active, or on hold, and no calls are ringing * or waiting. */ public static final int CALL_STATE_OFFHOOK = 2; @@ -609,13 +664,13 @@ public class TelephonyManager { public static final int DATA_CONNECTING = 1; /** Data connection state: Connected. IP traffic should be available. */ public static final int DATA_CONNECTED = 2; - /** Data connection state: Suspended. The connection is up, but IP - * traffic is temporarily unavailable. For example, in a 2G network, + /** Data connection state: Suspended. The connection is up, but IP + * traffic is temporarily unavailable. For example, in a 2G network, * data activity may be suspended when a voice call arrives. */ public static final int DATA_SUSPENDED = 3; /** - * Returns a constant indicating the current data connection state + * Returns a constant indicating the current data connection state * (cellular). * * @see #DATA_DISCONNECTED @@ -643,26 +698,26 @@ public class TelephonyManager { // /** - * Registers a listener object to receive notification of changes - * in specified telephony states. + * Registers a listener object to receive notification of changes + * in specified telephony states. *

        * To register a listener, pass a {@link PhoneStateListener} - * and specify at least one telephony state of interest in - * the events argument. - * + * and specify at least one telephony state of interest in + * the events argument. + * * At registration, and when a specified telephony state - * changes, the telephony manager invokes the appropriate - * callback method on the listener object and passes the + * changes, the telephony manager invokes the appropriate + * callback method on the listener object and passes the * current (udpated) values. *

        * To unregister a listener, pass the listener object and set the - * events argument to + * events argument to * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0). - * + * * @param listener The {@link PhoneStateListener} object to register * (or unregister) * @param events The telephony state(s) of interest to the listener, - * as a bitwise-OR combination of {@link PhoneStateListener} + * as a bitwise-OR combination of {@link PhoneStateListener} * LISTEN_ flags. */ public void listen(PhoneStateListener listener, int events) { diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java new file mode 100644 index 0000000000000000000000000000000000000000..189959b7dba5151b0f8ec8d3a01512e38a470491 --- /dev/null +++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java @@ -0,0 +1,146 @@ +/* + * 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 android.telephony.cdma; + +import android.os.Bundle; +import android.telephony.CellLocation; + +/** + * Represents the cell location on a GSM phone. + * @hide + */ +public class CdmaCellLocation extends CellLocation { + private int mBaseStationId = -1; + private int mBaseStationLatitude = -1; + private int mBaseStationLongitude = -1; + + /** + * Empty constructor. Initializes the LAC and CID to -1. + */ + public CdmaCellLocation() { + this.mBaseStationId = -1; + this.mBaseStationLatitude = -1; + this.mBaseStationLongitude = -1; + } + + /** + * Initialize the object from a bundle. + */ + public CdmaCellLocation(Bundle bundleWithValues) { + this.mBaseStationId = bundleWithValues.getInt("baseStationId"); + this.mBaseStationLatitude = bundleWithValues.getInt("baseStationLatitude"); + this.mBaseStationLongitude = bundleWithValues.getInt("baseStationLongitude"); + } + + /** + * @return cdma base station identification number, -1 if unknown + */ + public int getBaseStationId() { + return this.mBaseStationId; + } + + /** + * @return cdma base station latitude, -1 if unknown + */ + public int getBaseStationLatitude() { + return this.mBaseStationLatitude; + } + + /** + * @return cdma base station longitude, -1 if unknown + */ + public int getBaseStationLongitude() { + return this.mBaseStationLongitude; + } + + /** + * Invalidate this object. The cell location data is set to -1. + */ + public void setStateInvalid() { + this.mBaseStationId = -1; + this.mBaseStationLatitude = -1; + this.mBaseStationLongitude = -1; + } + + /** + * Set the cell location data. + */ + public void setCellLocationData(int baseStationId, int baseStationLatitude, + int baseStationLongitude) { + // The following values have to be written in the correct sequence + this.mBaseStationId = baseStationId; + this.mBaseStationLatitude = baseStationLatitude; //values[2]; + this.mBaseStationLongitude = baseStationLongitude; //values[3]; + } + + @Override + public int hashCode() { + return this.mBaseStationId ^ this.mBaseStationLatitude ^ this.mBaseStationLongitude; + } + + @Override + public boolean equals(Object o) { + CdmaCellLocation s; + + try { + s = (CdmaCellLocation)o; + } catch (ClassCastException ex) { + return false; + } + + if (o == null) { + return false; + } + + return (equalsHandlesNulls(this.mBaseStationId, s.mBaseStationId) && + equalsHandlesNulls(this.mBaseStationLatitude, s.mBaseStationLatitude) && + equalsHandlesNulls(this.mBaseStationLongitude, s.mBaseStationLongitude) + ); + } + + @Override + public String toString() { + return "[" + this.mBaseStationId + "," + + this.mBaseStationLatitude + "," + + this.mBaseStationLongitude + "]"; + } + + /** + * Test whether two objects hold the same data values or both are null + * + * @param a first obj + * @param b second obj + * @return true if two objects equal or both are null + */ + private static boolean equalsHandlesNulls(Object a, Object b) { + return (a == null) ? (b == null) : a.equals (b); + } + + /** + * Fill the cell location data into the intent notifier Bundle based on service state + * + * @param bundleToFill intent notifier Bundle + */ + public void fillInNotifierBundle(Bundle bundleToFill) { + bundleToFill.putInt("baseStationId", this.mBaseStationId); + bundleToFill.putInt("baseStationLatitude", this.mBaseStationLatitude); + bundleToFill.putInt("baseStationLongitude", this.mBaseStationLongitude); + } + +} + + diff --git a/telephony/java/android/telephony/cdma/package.html b/telephony/java/android/telephony/cdma/package.html new file mode 100644 index 0000000000000000000000000000000000000000..ee4af5e30f09e32ca992f2e342c3353e0c2f2164 --- /dev/null +++ b/telephony/java/android/telephony/cdma/package.html @@ -0,0 +1,5 @@ + + +Provides APIs for utilizing CDMA-specific telephony features. + + \ No newline at end of file diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java index fb9b73a4046707488f3f7a2cdbc8e5be418927d5..637a11cb819fb1ce02691a2148ea3c42ede59153 100644 --- a/telephony/java/android/telephony/gsm/GsmCellLocation.java +++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java @@ -17,14 +17,12 @@ package android.telephony.gsm; import android.os.Bundle; -import com.android.internal.telephony.Phone; import android.telephony.CellLocation; /** * Represents the cell location on a GSM phone. */ -public class GsmCellLocation extends CellLocation -{ +public class GsmCellLocation extends CellLocation { private int mLac; private int mCid; @@ -82,7 +80,7 @@ public class GsmCellLocation extends CellLocation @Override public boolean equals(Object o) { GsmCellLocation s; - + try { s = (GsmCellLocation)o; } catch (ClassCastException ex) { @@ -100,7 +98,7 @@ public class GsmCellLocation extends CellLocation public String toString() { return "["+ mLac + "," + mCid + "]"; } - + /** * Test whether two objects hold the same data values or both are null * diff --git a/telephony/java/android/telephony/gsm/SmsManager.java b/telephony/java/android/telephony/gsm/SmsManager.java index c63b5303309bd1f8adb62ddeb03fbb5187dac089..cdd707e629a22908ad168949d850431f8a61720c 100644 --- a/telephony/java/android/telephony/gsm/SmsManager.java +++ b/telephony/java/android/telephony/gsm/SmsManager.java @@ -17,28 +17,35 @@ package android.telephony.gsm; import android.app.PendingIntent; -import android.os.RemoteException; -import android.os.IServiceManager; -import android.os.ServiceManager; -import android.os.ServiceManagerNative; -import android.text.TextUtils; - -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; -import com.android.internal.telephony.gsm.ISms; -import com.android.internal.telephony.gsm.SimConstants; -import com.android.internal.telephony.gsm.SmsRawData; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; + /** * Manages SMS operations such as sending data, text, and pdu SMS messages. * Get this object by calling the static method SmsManager.getDefault(). + * @deprecated Replaced by android.telephony.SmsManager that supports both GSM and CDMA. */ -public final class SmsManager { +@Deprecated public final class SmsManager { private static SmsManager sInstance; + private android.telephony.SmsManager mSmsMgrProxy; + + /** Get the default instance of the SmsManager + * + * @return the default instance of the SmsManager + * @deprecated Use android.telephony.SmsManager. + */ + @Deprecated + public static final SmsManager getDefault() { + if (sInstance == null) { + sInstance = new SmsManager(); + } + return sInstance; + } + + private SmsManager() { + mSmsMgrProxy = android.telephony.SmsManager.getDefault(); + } /** * Send a text based SMS. @@ -55,28 +62,21 @@ public final class SmsManager { * RESULT_ERROR_RADIO_OFF * RESULT_ERROR_NULL_PDU. * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applicaitons, + * is NULL the caller will be checked against all unknown applications, * which cause smaller number of SMS to be sent in checking period. * @param deliveryIntent if not NULL this PendingIntent is * broadcast when the message is delivered to the recipient. The * raw pdu of the status report is in the extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or text are empty + * @deprecated Use android.telephony.SmsManager. */ - public void sendTextMessage( + @Deprecated + public final void sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { - if (TextUtils.isEmpty(destinationAddress)) { - throw new IllegalArgumentException("Invalid destinationAddress"); - } - - if (TextUtils.isEmpty(text)) { - throw new IllegalArgumentException("Invalid message body"); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( - scAddress, destinationAddress, text, (deliveryIntent != null)); - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + mSmsMgrProxy.sendTextMessage(destinationAddress, scAddress, text, + sentIntent, deliveryIntent); } /** @@ -86,55 +86,24 @@ public final class SmsManager { * @param text the original message. Must not be null. * @return an ArrayList of strings that, in order, * comprise the original message + * @deprecated Use android.telephony.SmsManager. */ - public ArrayList divideMessage(String text) { - int size = text.length(); - int[] params = SmsMessage.calculateLength(text, false); - /* SmsMessage.calculateLength returns an int[4] with: - * int[0] being the number of SMS's required, - * int[1] the number of code units used, - * int[2] is the number of code units remaining until the next message. - * int[3] is the encoding type that should be used for the message. - */ - int messageCount = params[0]; - int encodingType = params[3]; - ArrayList result = new ArrayList(messageCount); - - int start = 0; - int limit; - - if (messageCount > 1) { - 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; - } - - try { - while (start < size) { - int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType); - result.add(text.substring(start, end)); - start = end; - } - } catch (EncodeException e) { - // ignore it. - } - return result; + @Deprecated + public final ArrayList divideMessage(String text) { + return mSmsMgrProxy.divideMessage(text); } /** * Send a multi-part text based SMS. The callee should have already * divided the message into correctly sized parts by calling * divideMessage. - * + * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use * the current default SMSC * @param parts an ArrayList of strings that, in order, * comprise the original message - * @param sentIntents if not null, an ArrayList of + * @param sentIntents if not null, an ArrayList of * PendingIntents (one for each message part) that is * broadcast when the corresponding message part has been sent. * The result code will be Activity.RESULT_OK for success, @@ -145,44 +114,21 @@ public final class SmsManager { * The per-application based SMS control checks sentIntent. If sentIntent * is NULL the caller will be checked against all unknown applicaitons, * which cause smaller number of SMS to be sent in checking period. - * @param deliveryIntents if not null, an ArrayList of + * @param deliveryIntents if not null, an ArrayList of * PendingIntents (one for each message part) that is * broadcast when the corresponding message part has been delivered * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + * @deprecated Use android.telephony.SmsManager. */ - public void sendMultipartTextMessage( + @Deprecated + public final void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList parts, ArrayList sentIntents, ArrayList deliveryIntents) { - if (TextUtils.isEmpty(destinationAddress)) { - throw new IllegalArgumentException("Invalid destinationAddress"); - } - if (parts == null || parts.size() < 1) { - throw new IllegalArgumentException("Invalid message body"); - } - - if (parts.size() > 1) { - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - simISms.sendMultipartText(destinationAddress, scAddress, parts, - sentIntents, deliveryIntents); - } - } catch (RemoteException ex) { - // ignore it - } - } else { - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; - if (sentIntents != null && sentIntents.size() > 0) { - sentIntent = sentIntents.get(0); - } - if (deliveryIntents != null && deliveryIntents.size() > 0) { - deliveryIntent = deliveryIntents.get(0); - } - sendTextMessage(destinationAddress, scAddress, parts.get(0), - sentIntent, deliveryIntent); - } + mSmsMgrProxy.sendMultipartTextMessage(destinationAddress, scAddress, parts, + sentIntents, deliveryIntents); } /** @@ -208,70 +154,14 @@ public final class SmsManager { * raw pdu of the status report is in the extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or data are empty + * @deprecated Use android.telephony.SmsManager. */ - public void sendDataMessage( + @Deprecated + public final void sendDataMessage( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { - if (TextUtils.isEmpty(destinationAddress)) { - throw new IllegalArgumentException("Invalid destinationAddress"); - } - - if (data == null || data.length == 0) { - throw new IllegalArgumentException("Invalid message data"); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - destinationPort, data, (deliveryIntent != null)); - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); - } - - /** - * Send a raw SMS PDU. - * - * @param smsc the SMSC to send the message through, or NULL for the - * default SMSC - * @param pdu the raw PDU to send - * @param sentIntent if not NULL this PendingIntent is - * broadcast when the message is sucessfully sent, or failed. - * The result code will be Activity.RESULT_OK for success, - * or one of these errors: - * RESULT_ERROR_GENERIC_FAILURE - * RESULT_ERROR_RADIO_OFF - * RESULT_ERROR_NULL_PDU. - * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applicaitons, - * which cause smaller number of SMS to be sent in checking period. - * @param deliveryIntent if not NULL this PendingIntent is - * broadcast when the message is delivered to the recipient. The - * raw pdu of the status report is in the extended data ("pdu"). - * - */ - private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - simISms.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); - } - } catch (RemoteException ex) { - // ignore it - } - } - - /** - * Get the default instance of the SmsManager - * - * @return the default instance of the SmsManager - */ - public static SmsManager getDefault() { - if (sInstance == null) { - sInstance = new SmsManager(); - } - return sInstance; - } - - private SmsManager() { - // nothing to see here + mSmsMgrProxy.sendDataMessage(destinationAddress, scAddress, destinationPort, + data, sentIntent, deliveryIntent); } /** @@ -282,22 +172,12 @@ public final class SmsManager { * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) * @return true for success - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public boolean copyMessageToSim(byte[] smsc, byte[] pdu, int status) { - boolean success = false; - - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - success = simISms.copyMessageToSimEf(status, pdu, smsc); - } - } catch (RemoteException ex) { - // ignore it - } - - return success; + @Deprecated + public final boolean copyMessageToSim(byte[] smsc, byte[] pdu, int status) { + return mSmsMgrProxy.copyMessageToIcc(smsc, pdu, status); } /** @@ -305,26 +185,12 @@ public final class SmsManager { * * @param messageIndex is the record index of the message on SIM * @return true for success - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public boolean - deleteMessageFromSim(int messageIndex) { - boolean success = false; - byte[] pdu = new byte[SimConstants.SMS_RECORD_LENGTH-1]; - Arrays.fill(pdu, (byte)0xff); - - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - success = simISms.updateMessageOnSimEf(messageIndex, - STATUS_ON_SIM_FREE, pdu); - } - } catch (RemoteException ex) { - // ignore it - } - - return success; + @Deprecated + public final boolean deleteMessageFromSim(int messageIndex) { + return mSmsMgrProxy.deleteMessageFromIcc(messageIndex); } /** @@ -336,97 +202,59 @@ public final class SmsManager { * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) * @param pdu the raw PDU to store * @return true for success - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public boolean updateMessageOnSim(int messageIndex, int newStatus, - byte[] pdu) { - boolean success = false; - - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - success = simISms.updateMessageOnSimEf(messageIndex, newStatus, pdu); - } - } catch (RemoteException ex) { - // ignore it - } - - return success; + @Deprecated + public final boolean updateMessageOnSim(int messageIndex, int newStatus, byte[] pdu) { + return mSmsMgrProxy.updateMessageOnIcc(messageIndex, newStatus, pdu); } - /** * Retrieves all messages currently stored on SIM. - * * @return ArrayList of SmsMessage objects - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public ArrayList getAllMessagesFromSim() { - List records = null; + @Deprecated + public final ArrayList getAllMessagesFromSim() { + return mSmsMgrProxy.getAllMessagesFromIcc(); + } - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - records = simISms.getAllMessagesFromSimEf(); - } - } catch (RemoteException ex) { - // ignore it - } - - return createMessageListFromRawRecords(records); - } + /** Free space (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_FREE = 0; - /** - * Create a list of SmsMessages from a list of RawSmsData - * records returned by getAllMessagesFromSim() - * - * @param records SMS EF records, returned by - * getAllMessagesFromSim - * @return ArrayList of SmsMessage objects. - */ - private ArrayList createMessageListFromRawRecords(List records) { - ArrayList messages = new ArrayList(); - if (records != null) { - int count = records.size(); - for (int i = 0; i < count; i++) { - SmsRawData data = (SmsRawData)records.get(i); - // List contains all records, including "free" records (null) - if (data != null) { - SmsMessage sms = - SmsMessage.createFromEfRecord(i+1, data.getBytes()); - messages.add(sms); - } - } - } - return messages; - } + /** Received and read (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_READ = 1; - /** Free space (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_FREE = 0; + /** Received and unread (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_UNREAD = 3; - /** Received and read (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_READ = 1; + /** Stored and sent (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_SENT = 5; - /** Received and unread (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_UNREAD = 3; + /** Stored and unsent (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_UNSENT = 7; - /** Stored and sent (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_SENT = 5; + /** Generic failure cause + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_GENERIC_FAILURE = 1; - /** Stored and unsent (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_UNSENT = 7; + /** Failed because radio was explicitly turned off + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_RADIO_OFF = 2; + /** Failed because no pdu provided + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_NULL_PDU = 3; - // SMS send failure result codes + /** Failed because service is currently unavailable + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_NO_SERVICE = 4; - /** Generic failure cause */ - static public final int RESULT_ERROR_GENERIC_FAILURE = 1; - /** Failed because radio was explicitly turned off */ - static public final int RESULT_ERROR_RADIO_OFF = 2; - /** Failed because no pdu provided */ - static public final int RESULT_ERROR_NULL_PDU = 3; - /** Failed because service is currently unavailable */ - static public final int RESULT_ERROR_NO_SERVICE = 4; } diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java index c2e0165d9bc67fc81ccb25b71ae851ee69fac331..0928ddf6bc7c7c440dbda19cab2953c6601059a9 100644 --- a/telephony/java/android/telephony/gsm/SmsMessage.java +++ b/telephony/java/android/telephony/gsm/SmsMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * 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. @@ -16,327 +16,117 @@ package android.telephony.gsm; -import android.telephony.PhoneNumberUtils; -import android.util.Config; -import android.util.Log; -import android.telephony.PhoneNumberUtils; -import android.text.format.Time; +import android.os.Parcel; +import android.telephony.TelephonyManager; -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; -import com.android.internal.telephony.gsm.SimUtils; -import com.android.internal.telephony.gsm.SmsHeader; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; -import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; import java.util.Arrays; -class SmsAddress { - // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118 - static final int TON_UNKNOWN = 0; +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; - static final int TON_INTERNATIONAL = 1; - static final int TON_NATIONAL = 2; - - static final int TON_NETWORK = 3; - - static final int TON_SUBSCRIBER = 4; - - static final int TON_ALPHANUMERIC = 5; - - static final int TON_APPREVIATED = 6; - - static final int OFFSET_ADDRESS_LENGTH = 0; - - static final int OFFSET_TOA = 1; - - static final int OFFSET_ADDRESS_VALUE = 2; - - int ton; - - String address; - - byte[] origBytes; +/** + * A Short Message Service message. + * @deprecated Replaced by android.telephony.SmsMessage that supports both GSM and CDMA. + */ +@Deprecated +public class SmsMessage { + private static final boolean LOCAL_DEBUG = true; + private static final String LOG_TAG = "SMS"; /** - * New SmsAddress from TS 23.040 9.1.2.5 Address Field - * - * @param offset the offset of the Address-Length byte - * @param length the length in bytes rounded up, e.g. "2 + - * (addressLength + 1) / 2" + * SMS Class enumeration. + * See TS 23.038. + * @deprecated Use android.telephony.SmsMessage. */ - - SmsAddress(byte[] data, int offset, int length) { - origBytes = new byte[length]; - System.arraycopy(data, offset, origBytes, 0, length); - - // addressLength is the count of semi-octets, not bytes - int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff; - - int toa = origBytes[OFFSET_TOA] & 0xff; - ton = 0x7 & (toa >> 4); - - // TOA must have its high bit set - if ((toa & 0x80) != 0x80) { - throw new RuntimeException("Invalid TOA - high bit must be set"); - } - - if (isAlphanumeric()) { - // An alphanumeric address - int countSeptets = addressLength * 4 / 7; - - address = GsmAlphabet.gsm7BitPackedToString(origBytes, - OFFSET_ADDRESS_VALUE, countSeptets); - } else { - // TS 23.040 9.1.2.5 says - // that "the MS shall interpret reserved values as 'Unknown' - // but shall store them exactly as received" - - byte lastByte = origBytes[length - 1]; - - if ((addressLength & 1) == 1) { - // Make sure the final unused BCD digit is 0xf - origBytes[length - 1] |= 0xf0; - } - address = PhoneNumberUtils.calledPartyBCDToString(origBytes, - OFFSET_TOA, length - OFFSET_TOA); - - // And restore origBytes - origBytes[length - 1] = lastByte; - } - } - - public String getAddressString() { - return address; + @Deprecated + public enum MessageClass{ + UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; } - /** - * Returns true if this is an alphanumeric addres + /** Unknown encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isAlphanumeric() { - return ton == TON_ALPHANUMERIC; - } - - public boolean isNetworkSpecific() { - return ton == TON_NETWORK; - } + @Deprecated public static final int ENCODING_UNKNOWN = 0; - /** - * Returns true of this is a valid CPHS voice message waiting indicator - * address + /** 7-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isCphsVoiceMessageIndicatorAddress() { - // CPHS-style MWI message - // See CPHS 4.7 B.4.2.1 - // - // Basically: - // - // - Originating address should be 4 bytes long and alphanumeric - // - Decode will result with two chars: - // - Char 1 - // 76543210 - // ^ set/clear indicator (0 = clear) - // ^^^ type of indicator (000 = voice) - // ^^^^ must be equal to 0001 - // - Char 2: - // 76543210 - // ^ line number (0 = line 1) - // ^^^^^^^ set to 0 - // - // Remember, since the alpha address is stored in 7-bit compact form, - // the "line number" is really the top bit of the first address value - // byte - - return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4 - && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0; - } + @Deprecated public static final int ENCODING_7BIT = 1; - /** - * Returns true if this is a valid CPHS voice message waiting indicator - * address indicating a "set" of "indicator 1" of type "voice message - * waiting" + /** 8-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isCphsVoiceMessageSet() { - // 0x11 means "set" "voice message waiting" "indicator 1" - return isCphsVoiceMessageIndicatorAddress() - && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11; + @Deprecated public static final int ENCODING_8BIT = 2; - } - - /** - * Returns true if this is a valid CPHS voice message waiting indicator - * address indicationg a "clear" of "indicator 1" of type "voice message - * waiting" + /** 16-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isCphsVoiceMessageClear() { - // 0x10 means "clear" "voice message waiting" "indicator 1" - return isCphsVoiceMessageIndicatorAddress() - && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10; - - } - - public boolean couldBeEmailGateway() { - // Some carriers seems to send email gateway messages in this form: - // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5 - // PID: 0x00, Data coding scheme 0x03 - // So we just attempt to treat any message from an address length <= 4 - // as an email gateway - - return address.length() <= 4; - } - -} - -/** - * A Short Message Service message. - * - */ -public class SmsMessage { - static final String LOG_TAG = "GSM"; + @Deprecated public static final int ENCODING_16BIT = 3; - /** - * SMS Class enumeration. - * See TS 23.038. - * + /** The maximum number of payload bytes per message + * @deprecated Use android.telephony.SmsMessage. */ - public enum MessageClass { - UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; - } - - /** Unknown encoding scheme (see TS 23.038) */ - public static final int ENCODING_UNKNOWN = 0; - /** 7-bit encoding scheme (see TS 23.038) */ - public static final int ENCODING_7BIT = 1; - /** 8-bit encoding scheme (see TS 23.038) */ - public static final int ENCODING_8BIT = 2; - /** 16-bit encoding scheme (see TS 23.038) */ - public static final int ENCODING_16BIT = 3; - - /** The maximum number of payload bytes per message */ - public static final int MAX_USER_DATA_BYTES = 140; + @Deprecated public static final int MAX_USER_DATA_BYTES = 140; /** * The maximum number of payload bytes per message if a user data header * is present. This assumes the header only contains the * CONCATENATED_8_BIT_REFERENCE element. - * + * + * @deprecated Use android.telephony.SmsMessage. * @hide pending API Council approval to extend the public API */ - static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; + @Deprecated public 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; + /** The maximum number of payload septets per message + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int MAX_USER_DATA_SEPTETS = 160; /** * The maximum number of payload septets per message if a user data header * is present. This assumes the header only contains the * CONCATENATED_8_BIT_REFERENCE element. + * @deprecated Use android.telephony.SmsMessage. */ - public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; - - /** The address of the SMSC. May be null */ - String scAddress; - - /** The address of the sender */ - SmsAddress originatingAddress; - - /** The message body as a string. May be null if the message isn't text */ - String messageBody; - - String pseudoSubject; - - /** Non-null this is an email gateway message */ - String emailFrom; - - /** Non-null if this is an email gateway message */ - String emailBody; - - boolean isEmail; - - long scTimeMillis; + @Deprecated public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; - /** The raw PDU of the message */ - byte[] mPdu; - - /** The raw bytes for the user data section of the message */ - byte[] userData; - - SmsHeader userDataHeader; - - /** - * TP-Message-Type-Indicator - * 9.2.3 - */ - int mti; - - /** TP-Protocol-Identifier (TP-PID) */ - int protocolIdentifier; - - // TP-Data-Coding-Scheme - // see TS 23.038 - int dataCodingScheme; - - // TP-Reply-Path - // e.g. 23.040 9.2.2.1 - boolean replyPathPresent = false; - - // "Message Marked for Automatic Deletion Group" - // 23.038 Section 4 - boolean automaticDeletion; - - // "Message Waiting Indication Group" - // 23.038 Section 4 - private boolean isMwi; - - private boolean mwiSense; - - private boolean mwiDontStore; - - MessageClass messageClass; - - /** - * Indicates status for messages stored on the SIM. - */ - int statusOnSim = -1; - - /** - * Record index of message in the EF. + /** Contains actual SmsMessage. Only public for debugging and for framework layer. + * @deprecated Use android.telephony.SmsMessage. + * {@hide} */ - int indexOnSim = -1; - - /** TP-Message-Reference - Message Reference of sent message. @hide */ - public int messageRef; - - /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */ - boolean forSubmit; + @Deprecated public SmsMessageBase mWrappedSmsMessage; - /** The address of the receiver. */ - SmsAddress recipientAddress; - - /** Time when SMS-SUBMIT was delivered from SC to MSE. */ - long dischargeTimeMillis; - - /** - * TP-Status - status of a previously submitted SMS. - * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; - * see TS 23.040, 9.2.3.15 for description of other possible values. - */ - int status; + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public static class SubmitPdu { + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] encodedScAddress; // Null if not applicable. + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] encodedMessage; - /** - * TP-Status - status of a previously submitted SMS. - * This field is true iff the message is a SMS-STATUS-REPORT message. - */ - boolean isStatusReportMessage = false; + //Constructor + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public SubmitPdu() { + } - /** - * This class represents the encoded form of an outgoing SMS. - */ - public static class SubmitPdu { - public byte[] encodedScAddress; // Null if not applicable. - public byte[] encodedMessage; + /** @deprecated Use android.telephony.SmsMessage. + * {@hide} + */ + @Deprecated + protected SubmitPdu(SubmitPduBase spb) { + this.encodedMessage = spb.encodedMessage; + this.encodedScAddress = spb.encodedScAddress; + } + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String toString() { return "SubmitPdu: encodedScAddress = " + Arrays.toString(encodedScAddress) @@ -345,18 +135,33 @@ public class SmsMessage { } } + // Constructor + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public SmsMessage() { + this(getSmsFacility()); + } + + private SmsMessage(SmsMessageBase smb) { + mWrappedSmsMessage = smb; + } + /** * Create an SmsMessage from a raw PDU. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static SmsMessage createFromPdu(byte[] pdu) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(pdu); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); - return null; + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); } + + return new SmsMessage(wrappedMessage); } /** @@ -364,38 +169,70 @@ public class SmsMessage { * +CMT unsolicited response (PDU mode, of course) * +CMT: [<alpha>], * - * Only public for debugging - * + * Only public for debugging and for RIL + * @deprecated Use android.telephony.SmsMessage. * {@hide} */ - /* package */ public static SmsMessage newFromCMT(String[] lines) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(SimUtils.hexStringToBytes(lines[1])); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); - return null; + @Deprecated + public static SmsMessage newFromCMT(String[] lines){ + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); } + + return new SmsMessage(wrappedMessage); } - /* pacakge */ static SmsMessage newFromCMTI(String line) { - // the thinking here is not to read the message immediately - // FTA test case - Log.e(LOG_TAG, "newFromCMTI: not yet supported"); - return null; + /** @deprecated Use android.telephony.SmsMessage. + * @hide */ + @Deprecated + protected static SmsMessage newFromCMTI(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line); + } + + return new SmsMessage(wrappedMessage); } - /** @hide */ - /* package */ public static SmsMessage newFromCDS(String line) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(SimUtils.hexStringToBytes(line)); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); - return null; + /** @deprecated Use android.telephony.SmsMessage. + * @hide */ + @Deprecated + public static SmsMessage newFromCDS(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line); + } + + return new SmsMessage(wrappedMessage); + } + + /** @deprecated Use android.telephony.SmsMessage. + * @hide */ + @Deprecated + public static SmsMessage newFromParcel(Parcel p) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p); } + + return new SmsMessage(wrappedMessage); } /** @@ -405,51 +242,40 @@ public class SmsMessage { * returned by SmsManager.getAllMessagesFromSim + 1. * @param data Record data. * @return An SmsMessage representing the record. - * + * + * @deprecated Use android.telephony.SmsMessage. * @hide */ + @Deprecated public static SmsMessage createFromEfRecord(int index, byte[] data) { - try { - SmsMessage msg = new SmsMessage(); - - msg.indexOnSim = index; - - // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, - // or STORED_UNSENT - // See TS 51.011 10.5.3 - if ((data[0] & 1) == 0) { - Log.w(LOG_TAG, - "SMS parsing failed: Trying to parse a free record"); - return null; - } else { - msg.statusOnSim = data[0] & 0x07; - } + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - int size = data.length - 1; - - // Note: Data may include trailing FF's. That's OK; message - // should still parse correctly. - byte[] pdu = new byte[size]; - System.arraycopy(data, 1, pdu, 0, size); - msg.parsePdu(pdu); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); - return null; + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( + index, data); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( + index, data); } + + return new SmsMessage(wrappedMessage); } /** * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the * length in bytes (not hex chars) less the SMSC header + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static int getTPLayerLengthForPDU(String pdu) { - int len = pdu.length() / 2; - int smscLen = 0; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - smscLen = Integer.parseInt(pdu.substring(0, 2), 16); - - return len - smscLen - 1; + if (PHONE_TYPE_CDMA == activePhone) { + return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu); + } else { + return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu); + } } /** @@ -466,7 +292,9 @@ public class SmsMessage { * the number of code units used, and int[2] is the number of code * units remaining until the next message. int[3] is the encoding * type that should be used for the message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static int[] calculateLength(CharSequence messageBody, boolean use7bitOnly) { int ret[] = new int[4]; @@ -517,10 +345,10 @@ public class SmsMessage { * units remaining until the next message. int[3] is the encoding * type that should be used for the message. */ + @Deprecated public static int[] calculateLength(String messageBody, boolean use7bitOnly) { return calculateLength((CharSequence)messageBody, use7bitOnly); } - /** * Get an SMS-SUBMIT PDU for a destination address and a message @@ -529,92 +357,27 @@ public class SmsMessage { * @return a SubmitPdu containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. * @hide */ + @Deprecated public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, byte[] header) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - // Perform null parameter checks. - if (message == null || destinationAddress == null) { - return null; - } - - SubmitPdu ret = new SubmitPdu(); - // MTI = SMS-SUBMIT, UDHI = header != null - byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); - ByteArrayOutputStream bo = getSubmitPduHead( - scAddress, destinationAddress, mtiByte, - statusReportRequested, ret); - - try { - // First, try encoding it with the GSM alphabet - - // User Data (and length) - byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header); - - if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { - // Message too long - return null; - } - - // TP-Data-Coding-Scheme - // Default encoding, uncompressed - // To test writing messages to the SIM card, change this value 0x00 to 0x12, which - // means "bits 1 and 0 contain message class, and the class is 2". Note that this - // takes effect for the sender. In other words, messages sent by the phone with this - // change will end up on the receiver's SIM card. You can then send messages to - // yourself (on a phone with this change) and they'll end up on the SIM card. - bo.write(0x00); - - // (no TP-Validity-Period) - - bo.write(userData, 0, userData.length); - } catch (EncodeException ex) { - byte[] userData, textPart; - // Encoding to the 7-bit alphabet failed. Let's see if we can - // send it as a UCS-2 encoded message - - try { - textPart = message.getBytes("utf-16be"); - } catch (UnsupportedEncodingException uex) { - Log.e(LOG_TAG, - "Implausible UnsupportedEncodingException ", - uex); - return null; - } - - if (header != null) { - userData = new byte[header.length + textPart.length]; - - System.arraycopy(header, 0, userData, 0, header.length); - System.arraycopy(textPart, 0, userData, header.length, textPart.length); - } else { - userData = textPart; - } - - if (userData.length > MAX_USER_DATA_BYTES) { - // Message too long - return null; - } - - // TP-Data-Coding-Scheme - // Class 3, UCS-2 encoding, uncompressed - bo.write(0x0b); - - // (no TP-Validity-Period) - - // TP-UDL - bo.write(userData.length); - - bo.write(userData, 0, userData.length); + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); } - ret.encodedMessage = bo.toByteArray(); - return ret; + return new SubmitPdu(spb); } - /** * Get an SMS-SUBMIT PDU for a destination address and a message * @@ -622,12 +385,23 @@ public class SmsMessage { * @return a SubmitPdu containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static SubmitPdu getSubmitPdu(String scAddress, - String destinationAddress, String message, - boolean statusReportRequested) { + String destinationAddress, String message, boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } + + return new SubmitPdu(spb); } /** @@ -641,478 +415,105 @@ public class SmsMessage { * @return a SubmitPdu containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, short destinationPort, byte[] data, boolean statusReportRequested) { - if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { - Log.e(LOG_TAG, "SMS data message may only contain " - + (MAX_USER_DATA_BYTES - 7) + " bytes"); - return null; - } - - SubmitPdu ret = new SubmitPdu(); - ByteArrayOutputStream bo = getSubmitPduHead( - scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, - // TP-UDHI = true - statusReportRequested, ret); - - // TP-Data-Coding-Scheme - // No class, 8 bit data - bo.write(0x04); - - // (no TP-Validity-Period) - - // User data size - bo.write(data.length + 7); - - // User data header size - bo.write(0x06); // header is 6 octets - - // User data header, indicating the destination port - bo.write(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT); // port - // addressing - // header - bo.write(0x04); // each port is 2 octets - bo.write((destinationPort >> 8) & 0xFF); // MSB of destination port - bo.write(destinationPort & 0xFF); // LSB of destination port - bo.write(0x00); // MSB of originating port - bo.write(0x00); // LSB of originating port - - // User data - bo.write(data, 0, data.length); - - ret.encodedMessage = bo.toByteArray(); - return ret; - } + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - /** - * Create the beginning of a SUBMIT PDU. This is the part of the - * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, - * one of which takes a byte array and the other of which takes a - * String. - * - * @param scAddress Service Centre address. null == use default - * @param destinationAddress the address of the destination for the message - * @param mtiByte - * @param ret SubmitPdu containing the encoded SC - * address, if applicable, and the encoded message - */ - private static ByteArrayOutputStream getSubmitPduHead( - String scAddress, String destinationAddress, byte mtiByte, - boolean statusReportRequested, SubmitPdu ret) { - ByteArrayOutputStream bo = new ByteArrayOutputStream( - MAX_USER_DATA_BYTES + 40); - - // SMSC address with length octet, or 0 - if (scAddress == null) { - ret.encodedScAddress = null; + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); } else { - ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( - scAddress); - } - - // TP-Message-Type-Indicator (and friends) - if (statusReportRequested) { - // Set TP-Status-Report-Request bit. - mtiByte |= 0x20; - if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested"); - } - bo.write(mtiByte); - - // space for TP-Message-Reference - bo.write(0); - - byte[] daBytes; - - daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); - - // destination address length in BCD digits, ignoring TON byte and pad - // TODO Should be better. - bo.write((daBytes.length - 1) * 2 - - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); - - // destination address - bo.write(daBytes, 0, daBytes.length); - - // TP-Protocol-Identifier - bo.write(0); - return bo; - } - - static class PduParser { - byte pdu[]; - - int cur; - - SmsHeader userDataHeader; - - byte[] userData; - - int mUserDataSeptetPadding; - - int mUserDataSize; - - PduParser(String s) { - this(SimUtils.hexStringToBytes(s)); - } - - PduParser(byte[] pdu) { - this.pdu = pdu; - cur = 0; - mUserDataSeptetPadding = 0; - } - - /** - * Parse and return the SC address prepended to SMS messages coming via - * the TS 27.005 / AT interface. Returns null on invalid address - */ - String getSCAddress() { - int len; - String ret; - - // length of SC Address - len = getByte(); - - if (len == 0) { - // no SC address - ret = null; - } else { - // SC address - try { - ret = PhoneNumberUtils - .calledPartyBCDToString(pdu, cur, len); - } catch (RuntimeException tr) { - Log.d(LOG_TAG, "invalid SC address: ", tr); - ret = null; - } - } - - cur += len; - - return ret; - } - - /** - * returns non-sign-extended byte value - */ - int getByte() { - return pdu[cur++] & 0xff; - } - - /** - * Any address except the SC address (eg, originating address) See TS - * 23.040 9.1.2.5 - */ - SmsAddress getAddress() { - SmsAddress ret; - - // "The Address-Length field is an integer representation of - // the number field, i.e. excludes any semi octet containing only - // fill bits." - // The TOA field is not included as part of this - int addressLength = pdu[cur] & 0xff; - int lengthBytes = 2 + (addressLength + 1) / 2; - - ret = new SmsAddress(pdu, cur, lengthBytes); - - cur += lengthBytes; - - return ret; - } - - /** - * Parses an SC timestamp and returns a currentTimeMillis()-style - * timestamp - */ - - long getSCTimestampMillis() { - // TP-Service-Centre-Time-Stamp - int year = SimUtils.bcdByteToInt(pdu[cur++]); - int month = SimUtils.bcdByteToInt(pdu[cur++]); - int day = SimUtils.bcdByteToInt(pdu[cur++]); - int hour = SimUtils.bcdByteToInt(pdu[cur++]); - int minute = SimUtils.bcdByteToInt(pdu[cur++]); - int second = SimUtils.bcdByteToInt(pdu[cur++]); - - // For the timezone, the most significant bit of the - // least signficant nibble is the sign byte - // (meaning the max range of this field is 79 quarter-hours, - // which is more than enough) - - byte tzByte = pdu[cur++]; - - // Mask out sign bit. - int timezoneOffset = SimUtils - .bcdByteToInt((byte) (tzByte & (~0x08))); - - timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset - : -timezoneOffset; - - Time time = new Time(Time.TIMEZONE_UTC); - - // It's 2006. Should I really support years < 2000? - time.year = year >= 90 ? year + 1900 : year + 2000; - time.month = month - 1; - time.monthDay = day; - time.hour = hour; - time.minute = minute; - time.second = second; - - // Timezone offset is in quarter hours. - return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); - } - - /** - * Pulls the user data out of the PDU, and separates the payload from - * the header if there is one. - * - * @param hasUserDataHeader true if there is a user data header - * @param dataInSeptets true if the data payload is in septets instead - * of octets - * @return the number of septets or octets in the user data payload - */ - int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) - { - int offset = cur; - int userDataLength = pdu[offset++] & 0xff; - int headerSeptets = 0; - - if (hasUserDataHeader) { - int userDataHeaderLength = pdu[offset++] & 0xff; - - byte[] udh = new byte[userDataHeaderLength]; - System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); - userDataHeader = SmsHeader.parse(udh); - offset += userDataHeaderLength; - - int headerBits = (userDataHeaderLength + 1) * 8; - headerSeptets = headerBits / 7; - headerSeptets += (headerBits % 7) > 0 ? 1 : 0; - mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; - } - - /* - * Here we just create the user data length to be the remainder of - * the pdu minus the user data hearder. This is because the count - * could mean the number of uncompressed sepets if the userdata is - * encoded in 7-bit. - */ - userData = new byte[pdu.length - offset]; - System.arraycopy(pdu, offset, userData, 0, userData.length); - cur = offset; - - if (dataInSeptets) { - // Return the number of septets - 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; - } - } - - /** - * Returns the user data payload, not including the headers - * - * @return the user data payload, not including the headers - */ - byte[] getUserData() { - return userData; - } - - /** - * Returns the number of padding bits at the begining of the user data - * array before the start of the septets. - * - * @return the number of padding bits at the begining of the user data - * array before the start of the septets - */ - int getUserDataSeptetPadding() { - return mUserDataSeptetPadding; + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); } - /** - * Returns an object representing the user data headers - * - * @return an object representing the user data headers - * - * {@hide} - */ - SmsHeader getUserDataHeader() { - return userDataHeader; - } - -/* - XXX Not sure what this one is supposed to be doing, and no one is using - it. - String getUserDataGSM8bit() { - // System.out.println("remainder of pud:" + - // HexDump.dumpHexString(pdu, cur, pdu.length - cur)); - int count = pdu[cur++] & 0xff; - int size = pdu[cur++]; - - // skip over header for now - cur += size; - - if (pdu[cur - 1] == 0x01) { - int tid = pdu[cur++] & 0xff; - int type = pdu[cur++] & 0xff; - - size = pdu[cur++] & 0xff; - - int i = cur; - - while (pdu[i++] != '\0') { - } - - int length = i - cur; - String mimeType = new String(pdu, cur, length); - - cur += length; - - if (false) { - System.out.println("tid = 0x" + HexDump.toHexString(tid)); - System.out.println("type = 0x" + HexDump.toHexString(type)); - System.out.println("header size = " + size); - System.out.println("mimeType = " + mimeType); - System.out.println("remainder of header:" + - HexDump.dumpHexString(pdu, cur, (size - mimeType.length()))); - } - - cur += size - mimeType.length(); - - // System.out.println("data count = " + count + " cur = " + cur - // + " :" + HexDump.dumpHexString(pdu, cur, pdu.length - cur)); - - MMSMessage msg = MMSMessage.parseEncoding(mContext, pdu, cur, - pdu.length - cur); - } else { - System.out.println(new String(pdu, cur, pdu.length - cur - 1)); - } - - return SimUtils.bytesToHexString(pdu); - } -*/ - - /** - * Interprets the user data payload as pack GSM 7bit characters, and - * decodes them into a String. - * - * @param septetCount the number of septets in the user data payload - * @return a String with the decoded characters - */ - String getUserDataGSM7Bit(int septetCount) { - String ret; - - ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount, - mUserDataSeptetPadding); - - cur += (septetCount * 7) / 8; - - return ret; - } - - /** - * Interprets the user data payload as UCS2 characters, and - * decodes them into a String. - * - * @param byteCount the number of bytes in the user data payload - * @return a String with the decoded characters - */ - String getUserDataUCS2(int byteCount) { - String ret; - - try { - ret = new String(pdu, cur, byteCount, "utf-16"); - } catch (UnsupportedEncodingException ex) { - ret = ""; - Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); - } - - cur += byteCount; - return ret; - } - - boolean moreDataPresent() { - return (pdu.length > cur); - } + return new SubmitPdu(spb); } /** * Returns the address of the SMS service center that relayed this message * or null if there is none. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getServiceCenterAddress() { - return scAddress; + return mWrappedSmsMessage.getServiceCenterAddress(); } /** * Returns the originating address (sender) of this SMS message in String * form or null if unavailable + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getOriginatingAddress() { - if (originatingAddress == null) { - return null; - } - - return originatingAddress.getAddressString(); + return mWrappedSmsMessage.getOriginatingAddress(); } /** * Returns the originating address, or email from address if this message * was from an email gateway. Returns null if originating address * unavailable. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getDisplayOriginatingAddress() { - if (isEmail) { - return emailFrom; - } else { - return getOriginatingAddress(); - } + return mWrappedSmsMessage.getDisplayOriginatingAddress(); } /** * Returns the message body as a String, if it exists and is text based. * @return message body is there is one, otherwise null + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getMessageBody() { - return messageBody; + return mWrappedSmsMessage.getMessageBody(); } /** * Returns the class of this message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public MessageClass getMessageClass() { - return messageClass; + int index = mWrappedSmsMessage.getMessageClass().ordinal(); + + return MessageClass.values()[index]; } /** * Returns the message body, or email message body if this message was from * an email gateway. Returns null if message body unavailable. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getDisplayMessageBody() { - if (isEmail) { - return emailBody; - } else { - return getMessageBody(); - } + return mWrappedSmsMessage.getDisplayMessageBody(); } /** * Unofficial convention of a subject line enclosed in parens empty string * if not present + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getPseudoSubject() { - return pseudoSubject == null ? "" : pseudoSubject; + return mWrappedSmsMessage.getPseudoSubject(); } /** * Returns the service centre timestamp in currentTimeMillis() format + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public long getTimestampMillis() { - return scTimeMillis; + return mWrappedSmsMessage.getTimestampMillis(); } /** @@ -1120,129 +521,114 @@ public class SmsMessage { * * @return true if this message came through an email gateway and email * sender / subject / parsed body are available + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isEmail() { - return isEmail; + return mWrappedSmsMessage.isEmail(); } - /** + /** * @return if isEmail() is true, body of the email sent through the gateway. * null otherwise + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getEmailBody() { - return emailBody; + return mWrappedSmsMessage.getEmailBody(); } /** * @return if isEmail() is true, email from address of email sent through * the gateway. null otherwise + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getEmailFrom() { - return emailFrom; + return mWrappedSmsMessage.getEmailFrom(); } /** * Get protocol identifier. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public int getProtocolIdentifier() { - return protocolIdentifier; + return mWrappedSmsMessage.getProtocolIdentifier(); } /** - * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" - * SMS + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" SMS + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isReplace() { - return (protocolIdentifier & 0xc0) == 0x40 - && (protocolIdentifier & 0x3f) > 0 - && (protocolIdentifier & 0x3f) < 8; + return mWrappedSmsMessage.isReplace(); } /** * Returns true for CPHS MWI toggle message. * - * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section - * B.4.2 + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section B.4.2 + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isCphsMwiMessage() { - return originatingAddress.isCphsVoiceMessageClear() - || originatingAddress.isCphsVoiceMessageSet(); + return mWrappedSmsMessage.isCphsMwiMessage(); } /** * returns true if this message is a CPHS voicemail / message waiting * indicator (MWI) clear message + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isMWIClearMessage() { - if (isMwi && (mwiSense == false)) { - return true; - } - - return originatingAddress != null - && originatingAddress.isCphsVoiceMessageClear(); + return mWrappedSmsMessage.isMWIClearMessage(); } /** * returns true if this message is a CPHS voicemail / message waiting * indicator (MWI) set message + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isMWISetMessage() { - if (isMwi && (mwiSense == true)) { - return true; - } - - return originatingAddress != null - && originatingAddress.isCphsVoiceMessageSet(); + return mWrappedSmsMessage.isMWISetMessage(); } /** * returns true if this message is a "Message Waiting Indication Group: * Discard Message" notification and should not be stored. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isMwiDontStore() { - if (isMwi && mwiDontStore) { - return true; - } - - if (isCphsMwiMessage()) { - // See CPHS 4.2 Section B.4.2.1 - // If the user data is a single space char, do not store - // the message. Otherwise, store and display as usual - if (" ".equals(getMessageBody())) { - ; - } - return true; - } - - return false; + return mWrappedSmsMessage.isMwiDontStore(); } /** - * returns the user data section minus the user data header if one was - * present. + * returns the user data section minus the user data header if one was present. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] getUserData() { - return userData; + return mWrappedSmsMessage.getUserData(); } - /** - * Returns an object representing the user data header - * - * @return an object representing the user data header - * - * {@hide} - */ - public SmsHeader getUserDataHeader() { - return userDataHeader; - } + /* Not part of the SDK interface and only needed by specific classes: + protected SmsHeader getUserDataHeader() + */ /** * Returns the raw PDU for the message. * * @return the raw PDU for the message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] getPdu() { - return mPdu; + return mWrappedSmsMessage.getPdu(); } /** @@ -1254,369 +640,108 @@ public class SmsMessage { * SmsManager.STATUS_ON_SIM_UNREAD * SmsManager.STATUS_ON_SIM_SEND * SmsManager.STATUS_ON_SIM_UNSENT + * @deprecated Use android.telephony.SmsMessage and getStatusOnIcc instead. */ + @Deprecated public int getStatusOnSim() { - return statusOnSim; + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + * @deprecated Use android.telephony.SmsMessage. + * @hide + */ + @Deprecated + public int getStatusOnIcc() { + + return mWrappedSmsMessage.getStatusOnIcc(); } /** * Returns the record index of the message on the SIM (1-based index). * @return the record index of the message on the SIM, or -1 if this * SmsMessage was not created from a SIM SMS EF record. + * @deprecated Use android.telephony.SmsMessage and getIndexOnIcc instead. */ + @Deprecated public int getIndexOnSim() { - return indexOnSim; + return mWrappedSmsMessage.getIndexOnIcc(); } /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + * @deprecated Use android.telephony.SmsMessage. + * @hide + */ + @Deprecated + public int getIndexOnIcc() { + + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * GSM: * For an SMS-STATUS-REPORT message, this returns the status field from - * the status report. This field indicates the status of a previousely + * the status report. This field indicates the status of a previously * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a * description of values. + * CDMA: + * For not interfering with status codes from GSM, the value is + * shifted to the bits 31-16. + * The value is composed of an error class (bits 25-24) and a status code (bits 23-16). + * Possible codes are described in C.S0015-B, v2.0, 4.5.21. * * @return 0 indicates the previously sent message was received. - * See TS 23.040, 9.9.2.3.15 for a description of other possible - * values. + * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 + * for a description of other possible values. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public int getStatus() { - return status; + return mWrappedSmsMessage.getStatus(); } /** * Return true iff the message is a SMS-STATUS-REPORT message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isStatusReportMessage() { - return isStatusReportMessage; + return mWrappedSmsMessage.isStatusReportMessage(); } /** * Returns true iff the TP-Reply-Path bit is set in * this message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isReplyPathPresent() { - return replyPathPresent; - } - - /** - * TS 27.005 3.1, definition "In the case of SMS: 3GPP TS 24.011 [6] - * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: - * ME/TA converts each octet of TP data unit into two IRA character long - * hexad number (e.g. octet with integer value 42 is presented to TE as two - * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, - * something else... - */ - private void parsePdu(byte[] pdu) { - mPdu = pdu; - // Log.d(LOG_TAG, "raw sms mesage:"); - // Log.d(LOG_TAG, s); - - PduParser p = new PduParser(pdu); - - scAddress = p.getSCAddress(); - - if (scAddress != null) { - if (Config.LOGD) Log.d(LOG_TAG, "SMS SC address: " + scAddress); - } - - // TODO(mkf) support reply path, user data header indicator - - // TP-Message-Type-Indicator - // 9.2.3 - int firstByte = p.getByte(); - - mti = firstByte & 0x3; - switch (mti) { - // TP-Message-Type-Indicator - // 9.2.3 - case 0: - parseSmsDeliver(p, firstByte); - break; - case 2: - parseSmsStatusReport(p, firstByte); - break; - default: - // TODO(mkf) the rest of these - throw new RuntimeException("Unsupported message type"); - } - } - - /** - * Parses a SMS-STATUS-REPORT message. - * - * @param p A PduParser, cued past the first byte. - * @param firstByte The first byte of the PDU, which contains MTI, etc. - */ - private void parseSmsStatusReport(PduParser p, int firstByte) { - isStatusReportMessage = true; - - // TP-Status-Report-Qualifier bit == 0 for SUBMIT - forSubmit = (firstByte & 0x20) == 0x00; - // TP-Message-Reference - messageRef = p.getByte(); - // TP-Recipient-Address - recipientAddress = p.getAddress(); - // TP-Service-Centre-Time-Stamp - scTimeMillis = p.getSCTimestampMillis(); - // TP-Discharge-Time - dischargeTimeMillis = p.getSCTimestampMillis(); - // TP-Status - status = p.getByte(); - - // The following are optional fields that may or may not be present. - if (p.moreDataPresent()) { - // TP-Parameter-Indicator - int extraParams = p.getByte(); - int moreExtraParams = extraParams; - while ((moreExtraParams & 0x80) != 0) { - // We only know how to parse a few extra parameters, all - // indicated in the first TP-PI octet, so skip over any - // additional TP-PI octets. - moreExtraParams = p.getByte(); - } - // TP-Protocol-Identifier - if ((extraParams & 0x01) != 0) { - protocolIdentifier = p.getByte(); - } - // TP-Data-Coding-Scheme - if ((extraParams & 0x02) != 0) { - dataCodingScheme = p.getByte(); - } - // TP-User-Data-Length (implies existence of TP-User-Data) - if ((extraParams & 0x04) != 0) { - boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; - parseUserData(p, hasUserDataHeader); - } - } - } - - private void parseSmsDeliver(PduParser p, int firstByte) { - replyPathPresent = (firstByte & 0x80) == 0x80; - - originatingAddress = p.getAddress(); - - if (originatingAddress != null) { - if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " - + originatingAddress.address); - } - - // TP-Protocol-Identifier (TP-PID) - // TS 23.040 9.2.3.9 - protocolIdentifier = p.getByte(); - - // TP-Data-Coding-Scheme - // see TS 23.038 - dataCodingScheme = p.getByte(); - - if (Config.LOGV) { - Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier - + " data coding scheme: " + dataCodingScheme); - } - - scTimeMillis = p.getSCTimestampMillis(); - - if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); - - boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; - - parseUserData(p, hasUserDataHeader); + return mWrappedSmsMessage.isReplyPathPresent(); } - /** - * Parses the User Data of an SMS. - * - * @param p The current PduParser. - * @param hasUserDataHeader Indicates whether a header is present in the - * User Data. + /** This method returns the reference to a specific + * SmsMessage object, which is used for accessing its static methods. + * @return Specific SmsMessage. + * @deprecated Use android.telephony.SmsMessage. */ - private void parseUserData(PduParser p, boolean hasUserDataHeader) { - boolean hasMessageClass = false; - boolean userDataCompressed = false; - - int encodingType = ENCODING_UNKNOWN; - - // Look up the data encoding scheme - if ((dataCodingScheme & 0x80) == 0) { - // Bits 7..4 == 0xxx - automaticDeletion = (0 != (dataCodingScheme & 0x40)); - userDataCompressed = (0 != (dataCodingScheme & 0x20)); - hasMessageClass = (0 != (dataCodingScheme & 0x10)); - - if (userDataCompressed) { - Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " - + "(compression) " + (dataCodingScheme & 0xff)); - } else { - switch ((dataCodingScheme >> 2) & 0x3) { - case 0: // GSM 7 bit default alphabet - encodingType = ENCODING_7BIT; - break; - - case 2: // UCS 2 (16bit) - encodingType = ENCODING_16BIT; - break; - - case 1: // 8 bit data - case 3: // reserved - Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " - + (dataCodingScheme & 0xff)); - encodingType = ENCODING_8BIT; - break; - } - } - } else if ((dataCodingScheme & 0xf0) == 0xf0) { - automaticDeletion = false; - hasMessageClass = true; - userDataCompressed = false; - - if (0 == (dataCodingScheme & 0x04)) { - // GSM 7 bit default alphabet - encodingType = ENCODING_7BIT; - } else { - // 8 bit data - encodingType = ENCODING_8BIT; - } - } else if ((dataCodingScheme & 0xF0) == 0xC0 - || (dataCodingScheme & 0xF0) == 0xD0 - || (dataCodingScheme & 0xF0) == 0xE0) { - // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 - - // 0xC0 == 7 bit, don't store - // 0xD0 == 7 bit, store - // 0xE0 == UCS-2, store - - if ((dataCodingScheme & 0xF0) == 0xE0) { - encodingType = ENCODING_16BIT; - } else { - encodingType = ENCODING_7BIT; - } - - userDataCompressed = false; - boolean active = ((dataCodingScheme & 0x08) == 0x08); - - // bit 0x04 reserved - - if ((dataCodingScheme & 0x03) == 0x00) { - isMwi = true; - mwiSense = active; - mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0); - } else { - isMwi = false; - - Log.w(LOG_TAG, "MWI for fax, email, or other " - + (dataCodingScheme & 0xff)); - } + private static final SmsMessageBase getSmsFacility(){ + int activePhone = TelephonyManager.getDefault().getPhoneType(); + if (PHONE_TYPE_CDMA == activePhone) { + return new com.android.internal.telephony.cdma.SmsMessage(); } else { - Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " - + (dataCodingScheme & 0xff)); - } - - // set both the user data and the user data header. - int count = p.constructUserData(hasUserDataHeader, - encodingType == ENCODING_7BIT); - this.userData = p.getUserData(); - this.userDataHeader = p.getUserDataHeader(); - - switch (encodingType) { - case ENCODING_UNKNOWN: - case ENCODING_8BIT: - messageBody = null; - break; - - case ENCODING_7BIT: - messageBody = p.getUserDataGSM7Bit(count); - break; - - case ENCODING_16BIT: - messageBody = p.getUserDataUCS2(count); - break; - } - - if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); - - if (messageBody != null) { - parseMessageBody(); - } - - if (!hasMessageClass) { - messageClass = MessageClass.UNKNOWN; - } else { - switch (dataCodingScheme & 0x3) { - case 0: - messageClass = MessageClass.CLASS_0; - break; - case 1: - messageClass = MessageClass.CLASS_1; - break; - case 2: - messageClass = MessageClass.CLASS_2; - break; - case 3: - messageClass = MessageClass.CLASS_3; - break; - } - } - } - - private void parseMessageBody() { - if (originatingAddress.couldBeEmailGateway()) { - extractEmailAddressFromMessageBody(); - } - } - - /** - * Try to parse this message as an email gateway message -> Neither - * of the standard ways are currently supported: There are two ways - * specified in TS 23.040 Section 3.8 (not supported via this mechanism) - - * SMS message "may have its TP-PID set for internet electronic mail - MT - * SMS format: [] - "Depending on the - * nature of the gateway, the destination/origination address is either - * derived from the content of the SMS TP-OA or TP-DA field, or the - * TP-OA/TP-DA field contains a generic gateway address and the to/from - * address is added at the beginning as shown above." - multiple addreses - * separated by commas, no spaces - subject field delimited by '()' or '##' - * and '#' Section 9.2.3.24.11 - */ - private void extractEmailAddressFromMessageBody() { - - /* - * a little guesswork here. I haven't found doc for this. - * the format could be either - * - * 1. [x@y][ ]/[subject][ ]/[body] - * -or- - * 2. [x@y][ ]/[body] - */ - int slash = 0, slash2 = 0, atSymbol = 0; - - try { - slash = messageBody.indexOf(" /"); - if (slash == -1) { - return; - } - - atSymbol = messageBody.indexOf('@'); - if (atSymbol == -1 || atSymbol > slash) { - return; - } - - emailFrom = messageBody.substring(0, slash); - - slash2 = messageBody.indexOf(" /", slash + 2); - - if (slash2 == -1) { - pseudoSubject = null; - emailBody = messageBody.substring(slash + 2); - } else { - pseudoSubject = messageBody.substring(slash + 2, slash2); - emailBody = messageBody.substring(slash2 + 2); - } - - isEmail = true; - } catch (Exception ex) { - Log.w(LOG_TAG, - "extractEmailAddressFromMessageBody: exception slash=" - + slash + ", atSymbol=" + atSymbol + ", slash2=" - + slash2, ex); + return new com.android.internal.telephony.gsm.SmsMessage(); } } - } + diff --git a/telephony/java/com/android/internal/telephony/ATResponseParser.java b/telephony/java/com/android/internal/telephony/ATResponseParser.java index 93ec45588418671e5fd8cfee99a42027fd4710cf..fdb05262da4c064ffaf81875cd3f72a15ea915e5 100644 --- a/telephony/java/com/android/internal/telephony/ATResponseParser.java +++ b/telephony/java/com/android/internal/telephony/ATResponseParser.java @@ -34,7 +34,7 @@ public class ATResponseParser { this.line = line; } - + public boolean nextBoolean() { @@ -147,7 +147,7 @@ public class ATResponseParser } } - + /** Throws ATParseEx if whitespace extends to the end of string */ private char skipWhiteSpace (char c) diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl b/telephony/java/com/android/internal/telephony/AdnRecord.aidl similarity index 93% rename from telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl rename to telephony/java/com/android/internal/telephony/AdnRecord.aidl index 68d9a7c65693704e55cc9fcb255f77aa9be5cc10..b4a1a298aefd88e785ffa1ee86b8084cd5c75505 100644 --- a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl +++ b/telephony/java/com/android/internal/telephony/AdnRecord.aidl @@ -14,6 +14,7 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; parcelable AdnRecord; + diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.java b/telephony/java/com/android/internal/telephony/AdnRecord.java new file mode 100644 index 0000000000000000000000000000000000000000..5f40579b272a142d396970c5f70226a37273f516 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/AdnRecord.java @@ -0,0 +1,283 @@ +/* + * 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.os.Parcel; +import android.os.Parcelable; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import com.android.internal.telephony.GsmAlphabet; + + +/** + * + * Used to load or store ADNs (Abbreviated Dialing Numbers). + * + * {@hide} + * + */ +public class AdnRecord implements Parcelable { + static final String LOG_TAG = "GSM"; + + //***** Instance Variables + + String alphaTag = ""; + String number = ""; + int extRecord = 0xff; + int efid; // or 0 if none + int recordNumber; // or 0 if none + + + //***** Constants + + // In an ADN record, everything but the alpha identifier + // is in a footer that's 14 bytes + static final int FOOTER_SIZE_BYTES = 14; + + // Maximum size of the un-extended number field + static final int MAX_NUMBER_SIZE_BYTES = 11; + + static final int EXT_RECORD_LENGTH_BYTES = 13; + static final int EXT_RECORD_TYPE_ADDITIONAL_DATA = 2; + static final int EXT_RECORD_TYPE_MASK = 3; + static final int MAX_EXT_CALLED_PARTY_LENGTH = 0xa; + + // ADN offset + static final int ADN_BCD_NUMBER_LENGTH = 0; + static final int ADN_TON_AND_NPI = 1; + static final int ADN_DAILING_NUMBER_START = 2; + static final int ADN_DAILING_NUMBER_END = 11; + static final int ADN_CAPABILITY_ID = 12; + static final int ADN_EXTENSION_ID = 13; + + //***** Static Methods + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public AdnRecord createFromParcel(Parcel source) { + int efid; + int recordNumber; + String alphaTag; + String number; + + efid = source.readInt(); + recordNumber = source.readInt(); + alphaTag = source.readString(); + number = source.readString(); + + return new AdnRecord(efid, recordNumber, alphaTag, number); + } + + public AdnRecord[] newArray(int size) { + return new AdnRecord[size]; + } + }; + + + //***** Constructor + public + AdnRecord (byte[] record) { + this(0, 0, record); + } + + public + AdnRecord (int efid, int recordNumber, byte[] record) { + this.efid = efid; + this.recordNumber = recordNumber; + parseRecord(record); + } + + public + AdnRecord (String alphaTag, String number) { + this(0, 0, alphaTag, number); + } + + public + AdnRecord (int efid, int recordNumber, String alphaTag, String number) { + this.efid = efid; + this.recordNumber = recordNumber; + this.alphaTag = alphaTag; + this.number = number; + } + + //***** Instance Methods + + public String getAlphaTag() { + return alphaTag; + } + + public String getNumber() { + return number; + } + + public String toString() { + return "ADN Record '" + alphaTag + "' '" + number + "'"; + } + + public boolean isEmpty() { + return alphaTag.equals("") && number.equals(""); + } + + public boolean hasExtendedRecord() { + return extRecord != 0 && extRecord != 0xff; + } + + public boolean isEqual(AdnRecord adn) { + return ( alphaTag.equals(adn.getAlphaTag()) && + number.equals(adn.getNumber()) ); + } + //***** Parcelable Implementation + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(efid); + dest.writeInt(recordNumber); + dest.writeString(alphaTag); + dest.writeString(number); + } + + /** + * Build adn hex byte array based on record size + * The format of byte array is defined in 51.011 10.5.1 + * + * @param recordSize is the size X of EF record + * @return hex byte[recordSize] to be written to EF record + * return nulll for wrong format of dialing nubmer or tag + */ + public byte[] buildAdnString(int recordSize) { + byte[] bcdNumber; + byte[] byteTag; + byte[] adnString = null; + int footerOffset = recordSize - FOOTER_SIZE_BYTES; + + if (number == null || number.equals("") || + alphaTag == null || alphaTag.equals("")) { + + Log.w(LOG_TAG, "[buildAdnString] Empty alpha tag or number"); + adnString = new byte[recordSize]; + for (int i = 0; i < recordSize; i++) { + adnString[i] = (byte) 0xFF; + } + } else if (number.length() + > (ADN_DAILING_NUMBER_END - ADN_DAILING_NUMBER_START + 1) * 2) { + Log.w(LOG_TAG, + "[buildAdnString] Max length of dailing number is 20"); + } else if (alphaTag.length() > footerOffset) { + Log.w(LOG_TAG, + "[buildAdnString] Max length of tag is " + footerOffset); + } else { + + adnString = new byte[recordSize]; + for (int i = 0; i < recordSize; i++) { + adnString[i] = (byte) 0xFF; + } + + bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(number); + + System.arraycopy(bcdNumber, 0, adnString, + footerOffset + ADN_TON_AND_NPI, bcdNumber.length); + + adnString[footerOffset + ADN_BCD_NUMBER_LENGTH] + = (byte) (bcdNumber.length); + adnString[footerOffset + ADN_CAPABILITY_ID] + = (byte) 0xFF; // Capacility Id + adnString[footerOffset + ADN_EXTENSION_ID] + = (byte) 0xFF; // Extension Record Id + + byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag); + System.arraycopy(byteTag, 0, adnString, 0, byteTag.length); + + } + + return adnString; + } + + /** + * See TS 51.011 10.5.10 + */ + public void + appendExtRecord (byte[] extRecord) { + try { + if (extRecord.length != EXT_RECORD_LENGTH_BYTES) { + return; + } + + if ((extRecord[0] & EXT_RECORD_TYPE_MASK) + != EXT_RECORD_TYPE_ADDITIONAL_DATA) { + return; + } + + if ((0xff & extRecord[1]) > MAX_EXT_CALLED_PARTY_LENGTH) { + // invalid or empty record + return; + } + + number += PhoneNumberUtils.calledPartyBCDFragmentToString( + extRecord, 2, 0xff & extRecord[1]); + + // We don't support ext record chaining. + + } catch (RuntimeException ex) { + Log.w(LOG_TAG, "Error parsing AdnRecord ext record", ex); + } + } + + //***** Private Methods + + /** + * alphaTag and number are set to null on invalid format + */ + private void + parseRecord(byte[] record) { + try { + alphaTag = IccUtils.adnStringFieldToString( + record, 0, record.length - FOOTER_SIZE_BYTES); + + int footerOffset = record.length - FOOTER_SIZE_BYTES; + + int numberLength = 0xff & record[footerOffset]; + + if (numberLength > MAX_NUMBER_SIZE_BYTES) { + // Invalid number length + number = ""; + return; + } + + // Please note 51.011 10.5.1: + // + // "If the Dialling Number/SSC String does not contain + // a dialling number, e.g. a control string deactivating + // a service, the TON/NPI byte shall be set to 'FF' by + // the ME (see note 2)." + + number = PhoneNumberUtils.calledPartyBCDToString( + record, footerOffset + 1, numberLength); + + + extRecord = 0xff & record[record.length - 1]; + + } catch (RuntimeException ex) { + Log.w(LOG_TAG, "Error parsing AdnRecord", ex); + number = ""; + alphaTag = ""; + } + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/AdnRecordCache.java similarity index 91% rename from telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java rename to telephony/java/com/android/internal/telephony/AdnRecordCache.java index 9da18e37ae671a7dbff6a3ad78f0a35e3f73e81f..c270ae5087b83139ad54e278c04127ebd093cf89 100644 --- a/telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java +++ b/telephony/java/com/android/internal/telephony/AdnRecordCache.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.util.SparseArray; import android.util.Log; @@ -23,18 +23,18 @@ import android.os.Handler; import android.os.AsyncResult; import java.util.ArrayList; import java.util.Iterator; +import com.android.internal.telephony.IccConstants; /** * {@hide} */ -public final class AdnRecordCache extends Handler implements SimConstants -{ +public final class AdnRecordCache extends Handler implements IccConstants { //***** Instance Variables - GSMPhone phone; + PhoneBase phone; // Indexed by EF ID - SparseArray> adnLikeFiles + SparseArray> adnLikeFiles = new SparseArray>(); // People waiting for ADN-like files to be loaded @@ -52,9 +52,8 @@ public final class AdnRecordCache extends Handler implements SimConstants //***** Constructor - /*package*/ - AdnRecordCache(GSMPhone phone) - { + + public AdnRecordCache(PhoneBase phone) { this.phone = phone; } @@ -63,14 +62,12 @@ public final class AdnRecordCache extends Handler implements SimConstants /** * Called from SIMRecords.onRadioNotAvailable and SIMRecords.handleSimRefresh. */ - /*package*/ void - reset() - { + public void reset() { adnLikeFiles.clear(); clearWaiters(); clearUserWriters(); - + } private void clearWaiters() { @@ -95,29 +92,27 @@ public final class AdnRecordCache extends Handler implements SimConstants * @return List of AdnRecords for efid if we've already loaded them this * radio session, or null if we haven't */ - /*package*/ ArrayList - getRecordsIfLoaded(int efid) - { + public ArrayList + getRecordsIfLoaded(int efid) { return adnLikeFiles.get(efid); } /** - * Returns extension ef associated with ADN-like EF or -1 if + * Returns extension ef associated with ADN-like EF or -1 if * we don't know. * * See 3GPP TS 51.011 for this mapping */ private int - extensionEfForEf(int efid) - { + extensionEfForEf(int efid) { switch (efid) { case EF_MBDN: return EF_EXT6; case EF_ADN: return EF_EXT1; case EF_SDN: return EF_EXT3; case EF_FDN: return EF_EXT2; - case EF_MSISDN: return EF_EXT1; + case EF_MSISDN: return EF_EXT1; default: return -1; - } + } } private void sendErrorResponse(Message response, String errString) { @@ -138,7 +133,7 @@ public final class AdnRecordCache extends Handler implements SimConstants * @param response message to be posted when done * response.exception hold the exception in error */ - void updateAdnByIndex(int efid, AdnRecord adn, int recordIndex, String pin2, + public void updateAdnByIndex(int efid, AdnRecord adn, int recordIndex, String pin2, Message response) { int extensionEF = extensionEfForEf(efid); @@ -174,7 +169,7 @@ public final class AdnRecordCache extends Handler implements SimConstants * @param response message to be posted when done * response.exception hold the exception in error */ - void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn, + public void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn, String pin2, Message response) { int extensionEF; @@ -227,9 +222,8 @@ public final class AdnRecordCache extends Handler implements SimConstants * Responds with exception (in response) if efid is not a known ADN-like * record */ - /*package*/ void - requestLoadAllAdnLike (int efid, Message response) - { + public void + requestLoadAllAdnLike (int efid, Message response) { ArrayList waiters; ArrayList result; @@ -256,25 +250,25 @@ public final class AdnRecordCache extends Handler implements SimConstants waiters.add(response); return; } - + // Start loading efid - + waiters = new ArrayList(); waiters.add(response); adnLikeWaiters.put(efid, waiters); int extensionEF = extensionEfForEf(efid); - + if (extensionEF < 0) { // respond with error if not known ADN-like record if (response != null) { - AsyncResult.forMessage(response).exception + AsyncResult.forMessage(response).exception = new RuntimeException("EF is not known ADN-like EF:" + efid); response.sendToTarget(); } - + return; } @@ -285,8 +279,7 @@ public final class AdnRecordCache extends Handler implements SimConstants //***** Private methods private void - notifyWaiters(ArrayList waiters, AsyncResult ar) - { + notifyWaiters(ArrayList waiters, AsyncResult ar) { if (waiters == null) { return; diff --git a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..cfb5aaa84b399ee8e895461cb609ddbe0b596cf2 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java @@ -0,0 +1,285 @@ +/* + * 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 java.util.ArrayList; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + + +public class AdnRecordLoader extends Handler { + static String LOG_TAG; + + //***** Instance Variables + + PhoneBase phone; + int ef; + int extensionEF; + int pendingExtLoads; + Message userResponse; + String pin2; + + // For "load one" + int recordNumber; + + // for "load all" + ArrayList adns; // only valid after EVENT_ADN_LOAD_ALL_DONE + + // Either an AdnRecord or a reference to adns depending + // if this is a load one or load all operation + Object result; + + //***** Event Constants + + static final int EVENT_ADN_LOAD_DONE = 1; + static final int EVENT_EXT_RECORD_LOAD_DONE = 2; + static final int EVENT_ADN_LOAD_ALL_DONE = 3; + static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4; + static final int EVENT_UPDATE_RECORD_DONE = 5; + + //***** Constructor + + public AdnRecordLoader(PhoneBase phone) { + // The telephony unit-test cases may create AdnRecords + // in secondary threads + super(phone.getHandler().getLooper()); + + this.phone = phone; + LOG_TAG = phone.getPhoneName(); + } + + /** + * Resulting AdnRecord is placed in response.obj.result + * or response.obj.exception is set + */ + public void + loadFromEF(int ef, int extensionEF, int recordNumber, + Message response) { + this.ef = ef; + this.extensionEF = extensionEF; + this.recordNumber = recordNumber; + this.userResponse = response; + + phone.mIccFileHandler.loadEFLinearFixed( + ef, recordNumber, + obtainMessage(EVENT_ADN_LOAD_DONE)); + + } + + + /** + * Resulting ArrayList<adnRecord> is placed in response.obj.result + * or response.obj.exception is set + */ + public void + loadAllFromEF(int ef, int extensionEF, + Message response) { + this.ef = ef; + this.extensionEF = extensionEF; + this.userResponse = response; + + phone.mIccFileHandler.loadEFLinearFixedAll( + ef, + obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); + + } + + /** + * Write adn to a EF SIM record + * It will get the record size of EF record and compose hex adn array + * then write the hex array to EF record + * + * @param adn is set with alphaTag and phoneNubmer + * @param ef EF fileid + * @param extensionEF extension EF fileid + * @param recordNumber 1-based record index + * @param pin2 for CHV2 operations, must be null if pin2 is not needed + * @param response will be sent to its handler when completed + */ + public void + updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber, + String pin2, Message response) { + this.ef = ef; + this.extensionEF = extensionEF; + this.recordNumber = recordNumber; + this.userResponse = response; + this.pin2 = pin2; + + phone.mIccFileHandler.getEFLinearRecordSize( ef, + obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn)); + } + + //***** Overridden from Handler + + public void + handleMessage(Message msg) { + AsyncResult ar; + byte data[]; + AdnRecord adn; + + try { + switch (msg.what) { + case EVENT_EF_LINEAR_RECORD_SIZE_DONE: + ar = (AsyncResult)(msg.obj); + adn = (AdnRecord)(ar.userObj); + + if (ar.exception != null) { + throw new RuntimeException("get EF record size failed", + ar.exception); + } + + int[] recordSize = (int[])ar.result; + // recordSize is int[3] array + // int[0] is the record length + // int[1] is the total length of the EF file + // int[2] is the number of records in the EF file + // So int[0] * int[2] = int[1] + if (recordSize.length != 3 || recordNumber > recordSize[2]) { + throw new RuntimeException("get wrong EF record size format", + ar.exception); + } + + data = adn.buildAdnString(recordSize[0]); + + if(data == null) { + throw new RuntimeException("worong ADN format", + ar.exception); + } + + phone.mIccFileHandler.updateEFLinearFixed(ef, recordNumber, + data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); + + pendingExtLoads = 1; + + break; + case EVENT_UPDATE_RECORD_DONE: + ar = (AsyncResult)(msg.obj); + if (ar.exception != null) { + throw new RuntimeException("update EF adn record failed", + ar.exception); + } + pendingExtLoads = 0; + result = null; + break; + case EVENT_ADN_LOAD_DONE: + ar = (AsyncResult)(msg.obj); + data = (byte[])(ar.result); + + if (ar.exception != null) { + throw new RuntimeException("load failed", ar.exception); + } + + if (false) { + Log.d(LOG_TAG,"ADN EF: 0x" + + Integer.toHexString(ef) + + ":" + recordNumber + + "\n" + IccUtils.bytesToHexString(data)); + } + + adn = new AdnRecord(ef, recordNumber, data); + result = adn; + + if (adn.hasExtendedRecord()) { + // If we have a valid value in the ext record field, + // we're not done yet: we need to read the corresponding + // ext record and append it + + pendingExtLoads = 1; + + phone.mIccFileHandler.loadEFLinearFixed( + extensionEF, adn.extRecord, + obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); + } + break; + + case EVENT_EXT_RECORD_LOAD_DONE: + ar = (AsyncResult)(msg.obj); + data = (byte[])(ar.result); + adn = (AdnRecord)(ar.userObj); + + if (ar.exception != null) { + throw new RuntimeException("load failed", ar.exception); + } + + Log.d(LOG_TAG,"ADN extention EF: 0x" + + Integer.toHexString(extensionEF) + + ":" + adn.extRecord + + "\n" + IccUtils.bytesToHexString(data)); + + adn.appendExtRecord(data); + + pendingExtLoads--; + // result should have been set in + // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE + break; + + case EVENT_ADN_LOAD_ALL_DONE: + ar = (AsyncResult)(msg.obj); + ArrayList datas = (ArrayList)(ar.result); + + if (ar.exception != null) { + throw new RuntimeException("load failed", ar.exception); + } + + adns = new ArrayList(datas.size()); + result = adns; + pendingExtLoads = 0; + + for(int i = 0, s = datas.size() ; i < s ; i++) { + adn = new AdnRecord(ef, 1 + i, datas.get(i)); + adns.add(adn); + + if (adn.hasExtendedRecord()) { + // If we have a valid value in the ext record field, + // we're not done yet: we need to read the corresponding + // ext record and append it + + pendingExtLoads++; + + phone.mIccFileHandler.loadEFLinearFixed( + extensionEF, adn.extRecord, + obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); + } + } + break; + } + } catch (RuntimeException exc) { + if (userResponse != null) { + AsyncResult.forMessage(userResponse) + .exception = exc; + userResponse.sendToTarget(); + // Loading is all or nothing--either every load succeeds + // or we fail the whole thing. + userResponse = null; + } + return; + } + + if (userResponse != null && pendingExtLoads == 0) { + AsyncResult.forMessage(userResponse).result + = result; + + userResponse.sendToTarget(); + userResponse = null; + } + } + + +} diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java new file mode 100644 index 0000000000000000000000000000000000000000..fbc596cd73aa1ea72c96d618118c653a1c8a97d1 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/BaseCommands.java @@ -0,0 +1,589 @@ +/* + * 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.content.Context; +import android.os.RegistrantList; +import android.os.Registrant; +import android.os.Handler; +import android.os.AsyncResult; +import android.provider.Checkin; +import android.util.Config; +import android.util.Log; + +/** + * {@hide} + */ +public abstract class BaseCommands implements CommandsInterface { + static final String LOG_TAG = "RILB"; + + //***** Instance Variables + protected Context mContext; + protected RadioState mState = RadioState.RADIO_UNAVAILABLE; + protected Object mStateMonitor = new Object(); + + protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList(); + protected RegistrantList mOnRegistrants = new RegistrantList(); + protected RegistrantList mAvailRegistrants = new RegistrantList(); + protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList(); + protected RegistrantList mNotAvailRegistrants = new RegistrantList(); + protected RegistrantList mSIMReadyRegistrants = new RegistrantList(); + protected RegistrantList mSIMLockedRegistrants = new RegistrantList(); + protected RegistrantList mRUIMReadyRegistrants = new RegistrantList(); + protected RegistrantList mRUIMLockedRegistrants = new RegistrantList(); + protected RegistrantList mNVReadyRegistrants = new RegistrantList(); + protected RegistrantList mCallStateRegistrants = new RegistrantList(); + protected RegistrantList mNetworkStateRegistrants = new RegistrantList(); + protected RegistrantList mDataConnectionRegistrants = new RegistrantList(); + protected RegistrantList mRadioTechnologyChangedRegistrants = new RegistrantList(); + protected RegistrantList mIccStatusChangedRegistrants = new RegistrantList(); + protected RegistrantList mVoicePrivacyOnRegistrants = new RegistrantList(); + protected RegistrantList mVoicePrivacyOffRegistrants = new RegistrantList(); + protected Registrant mUnsolOemHookRawRegistrant; + protected Registrant mSMSRegistrant; + protected Registrant mNITZTimeRegistrant; + protected Registrant mSignalStrengthRegistrant; + protected Registrant mUSSDRegistrant; + protected Registrant mSmsOnSimRegistrant; + /** Registrant for handling SMS Status Reports */ + protected Registrant mSmsStatusRegistrant; + /** Registrant for handling Supplementary Service Notifications */ + protected Registrant mSsnRegistrant; + protected Registrant mStkSessionEndRegistrant; + protected Registrant mStkProCmdRegistrant; + protected Registrant mStkEventRegistrant; + protected Registrant mStkCallSetUpRegistrant; + /** Registrant for handling SIM/RUIM SMS storage full messages */ + protected Registrant mIccSmsFullRegistrant; + /** Registrant for handling Icc Refresh notifications */ + protected Registrant mIccRefreshRegistrant; + /** Registrant for handling RING notifications */ + protected Registrant mRingRegistrant; + /** Registrant for handling RESTRICTED STATE changed notification */ + protected Registrant mRestrictedStateRegistrant; + + //Network Mode received from PhoneFactory + protected int mNetworkMode; + //CDMA subscription received from PhoneFactory + protected int mCdmaSubscription; + //Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone. + protected int mPhoneType; + + + public BaseCommands(Context context) { + mContext = context; // May be null (if so we won't log statistics) + } + + //***** CommandsInterface implementation + + public RadioState getRadioState() { + return mState; + } + + + public void registerForRadioStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mRadioStateChangedRegistrants.add(r); + r.notifyRegistrant(); + } + } + + public void unregisterForRadioStateChanged(Handler h) { + synchronized (mStateMonitor) { + mRadioStateChangedRegistrants.remove(h); + } + } + + public void registerForOn(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mOnRegistrants.add(r); + + if (mState.isOn()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + public void unregisterForOn(Handler h) { + synchronized (mStateMonitor) { + mOnRegistrants.remove(h); + } + } + + + public void registerForAvailable(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mAvailRegistrants.add(r); + + if (mState.isAvailable()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForAvailable(Handler h) { + synchronized(mStateMonitor) { + mAvailRegistrants.remove(h); + } + } + + public void registerForNotAvailable(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mNotAvailRegistrants.add(r); + + if (!mState.isAvailable()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForNotAvailable(Handler h) { + synchronized (mStateMonitor) { + mNotAvailRegistrants.remove(h); + } + } + + public void registerForOffOrNotAvailable(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mOffOrNotAvailRegistrants.add(r); + + if (mState == RadioState.RADIO_OFF || !mState.isAvailable()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + public void unregisterForOffOrNotAvailable(Handler h) { + synchronized(mStateMonitor) { + mOffOrNotAvailRegistrants.remove(h); + } + } + + + /** Any transition into SIM_READY */ + public void registerForSIMReady(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mSIMReadyRegistrants.add(r); + + if (mState.isSIMReady()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForSIMReady(Handler h) { + synchronized (mStateMonitor) { + mSIMReadyRegistrants.remove(h); + } + } + + /** Any transition into RUIM_READY */ + public void registerForRUIMReady(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mRUIMReadyRegistrants.add(r); + + if (mState.isRUIMReady()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForRUIMReady(Handler h) { + synchronized(mStateMonitor) { + mRUIMReadyRegistrants.remove(h); + } + } + + /** Any transition into NV_READY */ + public void registerForNVReady(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mNVReadyRegistrants.add(r); + + if (mState.isNVReady()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForNVReady(Handler h) { + synchronized (mStateMonitor) { + mNVReadyRegistrants.remove(h); + } + } + + public void registerForSIMLockedOrAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mSIMLockedRegistrants.add(r); + + if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForSIMLockedOrAbsent(Handler h) { + synchronized (mStateMonitor) { + mSIMLockedRegistrants.remove(h); + } + } + + public void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + synchronized (mStateMonitor) { + mRUIMLockedRegistrants.add(r); + + if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + } + + public void unregisterForRUIMLockedOrAbsent(Handler h) { + synchronized (mStateMonitor) { + mRUIMLockedRegistrants.remove(h); + } + } + + public void registerForCallStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mCallStateRegistrants.add(r); + } + + public void unregisterForCallStateChanged(Handler h) { + mCallStateRegistrants.remove(h); + } + + public void registerForNetworkStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mNetworkStateRegistrants.add(r); + } + + public void unregisterForNetworkStateChanged(Handler h) { + mNetworkStateRegistrants.remove(h); + } + + public void registerForDataStateChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mDataConnectionRegistrants.add(r); + } + + public void unregisterForDataStateChanged(Handler h) { + mDataConnectionRegistrants.remove(h); + } + + public void registerForRadioTechnologyChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mRadioTechnologyChangedRegistrants.add(r); + } + + public void unregisterForRadioTechnologyChanged(Handler h) { + mRadioTechnologyChangedRegistrants.remove(h); + } + + public void registerForIccStatusChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mIccStatusChangedRegistrants.add(r); + } + + public void unregisterForIccStatusChanged(Handler h) { + mIccStatusChangedRegistrants.remove(h); + } + + public void setOnNewSMS(Handler h, int what, Object obj) { + mSMSRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnNewSMS(Handler h) { + mSMSRegistrant.clear(); + } + + public void setOnSmsOnSim(Handler h, int what, Object obj) { + mSmsOnSimRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSmsOnSim(Handler h) { + mSmsOnSimRegistrant.clear(); + } + + public void setOnSmsStatus(Handler h, int what, Object obj) { + mSmsStatusRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSmsStatus(Handler h) { + mSmsStatusRegistrant.clear(); + } + + public void setOnSignalStrengthUpdate(Handler h, int what, Object obj) { + mSignalStrengthRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSignalStrengthUpdate(Handler h) { + mSignalStrengthRegistrant.clear(); + } + + public void setOnNITZTime(Handler h, int what, Object obj) { + mNITZTimeRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnNITZTime(Handler h) { + mNITZTimeRegistrant.clear(); + } + + public void setOnUSSD(Handler h, int what, Object obj) { + mUSSDRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnUSSD(Handler h) { + mUSSDRegistrant.clear(); + } + + public void setOnSuppServiceNotification(Handler h, int what, Object obj) { + mSsnRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnSuppServiceNotification(Handler h) { + mSsnRegistrant.clear(); + } + + public void setOnStkSessionEnd(Handler h, int what, Object obj) { + mStkSessionEndRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkSessionEnd(Handler h) { + mStkSessionEndRegistrant.clear(); + } + + public void setOnStkProactiveCmd(Handler h, int what, Object obj) { + mStkProCmdRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkProactiveCmd(Handler h) { + mStkProCmdRegistrant.clear(); + } + + public void setOnStkEvent(Handler h, int what, Object obj) { + mStkEventRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkEvent(Handler h) { + mStkEventRegistrant.clear(); + } + + public void setOnStkCallSetUp(Handler h, int what, Object obj) { + mStkCallSetUpRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnStkCallSetUp(Handler h) { + mStkCallSetUpRegistrant.clear(); + } + + public void setOnIccSmsFull(Handler h, int what, Object obj) { + mIccSmsFullRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnIccSmsFull(Handler h) { + mIccSmsFullRegistrant.clear(); + } + + public void setOnIccRefresh(Handler h, int what, Object obj) { + mIccRefreshRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnIccRefresh(Handler h) { + mIccRefreshRegistrant.clear(); + } + + public void setOnCallRing(Handler h, int what, Object obj) { + mRingRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnCallRing(Handler h) { + mRingRegistrant.clear(); + } + + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mVoicePrivacyOnRegistrants.add(r); + } + + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mVoicePrivacyOnRegistrants.remove(h); + } + + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mVoicePrivacyOffRegistrants.add(r); + } + + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mVoicePrivacyOffRegistrants.remove(h); + } + + public void setOnRestrictedStateChanged(Handler h, int what, Object obj) { + mRestrictedStateRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnRestrictedStateChanged(Handler h) { + mRestrictedStateRegistrant.clear(); + } + + public void setOnUnsolOemHookRaw(Handler h, int what, Object obj) { + mUnsolOemHookRawRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnUnsolOemHookRaw(Handler h) { + mUnsolOemHookRawRegistrant.clear(); + } + + //***** Protected Methods + /** + * Store new RadioState and send notification based on the changes + * + * This function is called only by RIL.java when receiving unsolicited + * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED + * + * RadioState has 5 values : RADIO_OFF, RADIO_UNAVAILABLE, SIM_NOT_READY, + * SIM_LOCKED_OR_ABSENT, and SIM_READY. + * + * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED + */ + protected void setRadioState(RadioState newState) { + RadioState oldState; + + synchronized (mStateMonitor) { + if (Config.LOGV) { + Log.v(LOG_TAG, "setRadioState old: " + mState + + " new " + newState); + } + + oldState = mState; + mState = newState; + + if (oldState == mState) { + // no state transition + return; + } + + if (mContext != null && + newState == RadioState.RADIO_UNAVAILABLE && + oldState != RadioState.RADIO_OFF) { + Checkin.updateStats(mContext.getContentResolver(), + Checkin.Stats.Tag.PHONE_RADIO_RESETS, 1, 0.0); + } + + mRadioStateChangedRegistrants.notifyRegistrants(); + + if (mState.isAvailable() && !oldState.isAvailable()) { + Log.d(LOG_TAG,"Notifying: radio available"); + mAvailRegistrants.notifyRegistrants(); + onRadioAvailable(); + } + + if (!mState.isAvailable() && oldState.isAvailable()) { + Log.d(LOG_TAG,"Notifying: radio not available"); + mNotAvailRegistrants.notifyRegistrants(); + } + + if (mState.isSIMReady() && !oldState.isSIMReady()) { + Log.d(LOG_TAG,"Notifying: SIM ready"); + mSIMReadyRegistrants.notifyRegistrants(); + } + + if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { + Log.d(LOG_TAG,"Notifying: SIM locked or absent"); + mSIMLockedRegistrants.notifyRegistrants(); + } + + if (mState.isRUIMReady() && !oldState.isRUIMReady()) { + Log.d(LOG_TAG,"Notifying: RUIM ready"); + mRUIMReadyRegistrants.notifyRegistrants(); + } + + if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) { + Log.d(LOG_TAG,"Notifying: RUIM locked or absent"); + mRUIMLockedRegistrants.notifyRegistrants(); + } + if (mState.isNVReady() && !oldState.isNVReady()) { + Log.d(LOG_TAG,"Notifying: NV ready"); + mNVReadyRegistrants.notifyRegistrants(); + } + + if (mState.isOn() && !oldState.isOn()) { + Log.d(LOG_TAG,"Notifying: Radio On"); + mOnRegistrants.notifyRegistrants(); + } + + if ((!mState.isOn() || !mState.isAvailable()) + && !((!oldState.isOn() || !oldState.isAvailable())) + ) { + Log.d(LOG_TAG,"Notifying: radio off or not available"); + mOffOrNotAvailRegistrants.notifyRegistrants(); + } + + /* Radio Technology Change events + * NOTE: isGsm and isCdma have no common states in RADIO_OFF or RADIO_UNAVAILABLE; the + * current phone is determined by mPhoneType + * NOTE: at startup no phone have been created and the RIL determines the mPhoneType + * looking based on the networkMode set by the PhoneFactory in the constructor + */ + + if (mState.isGsm() && oldState.isCdma()) { + Log.d(LOG_TAG,"Notifying: radio technology change CDMA to GSM"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isGsm() && !oldState.isOn() && (mPhoneType == RILConstants.CDMA_PHONE)) { + Log.d(LOG_TAG,"Notifying: radio technology change CDMA OFF to GSM"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isCdma() && oldState.isGsm()) { + Log.d(LOG_TAG,"Notifying: radio technology change GSM to CDMA"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isCdma() && !oldState.isOn() && (mPhoneType == RILConstants.GSM_PHONE)) { + Log.d(LOG_TAG,"Notifying: radio technology change GSM OFF to CDMA"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + } + } + + protected void onRadioAvailable() { + } +} diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java index 82aeb25dead1d129c6b749f4d4a7c5d0d3dad562..70471b63415385e0e358f981dfb8a90597e325fc 100644 --- a/telephony/java/com/android/internal/telephony/Call.java +++ b/telephony/java/com/android/internal/telephony/Call.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import java.util.List; + /** * {@hide} */ @@ -39,6 +40,13 @@ public abstract class Call { } } + + /* Instance Variables */ + + public State state = State.IDLE; + + + /* Instance Methods */ /** Do not modify the List result!!! This list is not yours to keep @@ -46,36 +54,46 @@ public abstract class Call { */ public abstract List getConnections(); - public abstract State getState(); public abstract Phone getPhone(); + public abstract boolean isMultiparty(); + public abstract void hangup() throws CallStateException; + /** * hasConnection - * + * * @param c a Connection object * @return true if the call contains the connection object passed in */ public boolean hasConnection(Connection c) { return c.getCall() == this; } - + /** * hasConnections * @return true if the call contains one or more connections */ public boolean hasConnections() { List connections = getConnections(); - + if (connections == null) { return false; } - + return connections.size() > 0; } - + + /** + * getState + * @return state of class call + */ + public State getState() { + return state; + } + /** * isIdle - * + * * FIXME rename * @return true if the call contains only disconnected connections (if any) */ @@ -93,27 +111,27 @@ public abstract class Call { long time = Long.MAX_VALUE; Connection c; Connection earliest = null; - + l = getConnections(); - + if (l.size() == 0) { return null; } - + for (int i = 0, s = l.size() ; i < s ; i++) { c = (Connection) l.get(i); long t; - + t = c.getCreateTime(); - + if (t < time) { earliest = c; } } - + return earliest; } - + public long getEarliestCreateTime() { List l; @@ -160,9 +178,6 @@ public abstract class Call { return time; } - public abstract boolean isMultiparty(); - - public abstract void hangup() throws CallStateException; public boolean isDialingOrAlerting() { diff --git a/telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java b/telephony/java/com/android/internal/telephony/CallForwardInfo.java similarity index 93% rename from telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java rename to telephony/java/com/android/internal/telephony/CallForwardInfo.java index bf31b138cc7168532ed599b065fb053e8e7703bc..8b853b0d124bb48ab036d073d4e0f84b1a0f878f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java +++ b/telephony/java/com/android/internal/telephony/CallForwardInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.telephony.PhoneNumberUtils; @@ -23,8 +23,7 @@ import android.telephony.PhoneNumberUtils; * * {@hide} */ -public class CallForwardInfo -{ +public class CallForwardInfo { public int status; /*1 = active, 0 = not active */ public int reason; /* from TS 27.007 7.11 "reason" */ public int serviceClass; /* Sum of CommandsInterface.SERVICE_CLASS */ @@ -32,8 +31,7 @@ public class CallForwardInfo public String number; /* "number" from TS 27.007 7.11 */ public int timeSeconds; /* for CF no reply only */ - public String toString() - { + public String toString() { return super.toString() + (status == 0 ? " not active " : " active ") + " reason: " + reason + " serviceClass: " + serviceClass diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java new file mode 100644 index 0000000000000000000000000000000000000000..eb339f869b8ab313cc8ddb5d4d031bc131dde5fe --- /dev/null +++ b/telephony/java/com/android/internal/telephony/CallTracker.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.internal.telephony; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.android.internal.telephony.CommandException; + + +/** + * {@hide} + */ +public abstract class CallTracker extends Handler { + + private static final boolean DBG_POLL = false; + + //***** Constants + + static final int POLL_DELAY_MSEC = 250; + + protected int pendingOperations; + protected boolean needsPoll; + protected Message lastRelevantPoll; + + public CommandsInterface cm; + + + //***** Events + + protected static final int EVENT_POLL_CALLS_RESULT = 1; + protected static final int EVENT_CALL_STATE_CHANGE = 2; + protected static final int EVENT_REPOLL_AFTER_DELAY = 3; + protected static final int EVENT_OPERATION_COMPLETE = 4; + protected static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5; + + protected static final int EVENT_SWITCH_RESULT = 8; + protected static final int EVENT_RADIO_AVAILABLE = 9; + protected static final int EVENT_RADIO_NOT_AVAILABLE = 10; + protected static final int EVENT_CONFERENCE_RESULT = 11; + protected static final int EVENT_SEPARATE_RESULT = 12; + protected static final int EVENT_ECT_RESULT = 13; + + + protected void pollCallsWhenSafe() { + needsPoll = true; + + if (checkNoOperationsPending()) { + lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); + cm.getCurrentCalls(lastRelevantPoll); + } + } + + protected void + pollCallsAfterDelay() { + Message msg = obtainMessage(); + + msg.what = EVENT_REPOLL_AFTER_DELAY; + sendMessageDelayed(msg, POLL_DELAY_MSEC); + } + + protected boolean + isCommandExceptionRadioNotAvailable(Throwable e) { + return e != null && e instanceof CommandException + && ((CommandException)e).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE; + } + + protected abstract void handlePollCalls(AsyncResult ar); + + protected void handleRadioAvailable() { + pollCallsWhenSafe(); + } + + /** + * Obtain a complete message that indicates that this operation + * does not require polling of getCurrentCalls(). However, if other + * operations that do need getCurrentCalls() are pending or are + * scheduled while this operation is pending, the invocation + * of getCurrentCalls() will be postponed until this + * operation is also complete. + */ + protected Message + obtainNoPollCompleteMessage(int what) { + pendingOperations++; + lastRelevantPoll = null; + return obtainMessage(what); + } + + /** + * @return true if we're idle or there's a call to getCurrentCalls() pending + * but nothing else + */ + private boolean + checkNoOperationsPending() { + if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" + + pendingOperations); + return pendingOperations == 0; + } + + + //***** Overridden from Handler + public abstract void handleMessage (Message msg); + + protected abstract void log(String msg); + +} diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 145e5d86098eda2066571f50a915c4e45a2ec94d..04da9f7193324b8950cd163e84ba063ad48af219 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -37,7 +37,7 @@ import android.util.Log; public class CallerInfoAsyncQuery { private static final boolean DBG = false; - private static final String LOG_TAG = "CallerInfoAsyncQuery"; + private static final String LOG_TAG = "PHONE"; private static final int EVENT_NEW_QUERY = 1; private static final int EVENT_ADD_LISTENER = 2; diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandException.java b/telephony/java/com/android/internal/telephony/CommandException.java similarity index 77% rename from telephony/java/com/android/internal/telephony/gsm/CommandException.java rename to telephony/java/com/android/internal/telephony/CommandException.java index 5cf48f36cc1310f53277e44d5acaee8cb4f7f43d..a5d11cf250d80afae0f7bae53ae73f20e4afc41f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CommandException.java +++ b/telephony/java/com/android/internal/telephony/CommandException.java @@ -14,15 +14,16 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; + +import com.android.internal.telephony.RILConstants; import android.util.Log; /** * {@hide} */ -public class CommandException extends RuntimeException -{ +public class CommandException extends RuntimeException { private Error e; public enum Error { @@ -38,30 +39,28 @@ public class CommandException extends RuntimeException SMS_FAIL_RETRY, } - public CommandException(Error e) - { + public CommandException(Error e) { super(e.toString()); this.e = e; } public static CommandException - fromRilErrno(int ril_errno) - { + fromRilErrno(int ril_errno) { switch(ril_errno) { case RILConstants.SUCCESS: return null; - case RILConstants.RIL_ERRNO_INVALID_RESPONSE: + case RILConstants.RIL_ERRNO_INVALID_RESPONSE: return new CommandException(Error.INVALID_RESPONSE); - case RILConstants.RADIO_NOT_AVAILABLE: + case RILConstants.RADIO_NOT_AVAILABLE: return new CommandException(Error.RADIO_NOT_AVAILABLE); - case RILConstants.GENERIC_FAILURE: + case RILConstants.GENERIC_FAILURE: return new CommandException(Error.GENERIC_FAILURE); - case RILConstants.PASSWORD_INCORRECT: + case RILConstants.PASSWORD_INCORRECT: return new CommandException(Error.PASSWORD_INCORRECT); - case RILConstants.SIM_PIN2: + case RILConstants.SIM_PIN2: return new CommandException(Error.SIM_PIN2); - case RILConstants.SIM_PUK2: + case RILConstants.SIM_PUK2: return new CommandException(Error.SIM_PUK2); - case RILConstants.REQUEST_NOT_SUPPORTED: + case RILConstants.REQUEST_NOT_SUPPORTED: return new CommandException(Error.REQUEST_NOT_SUPPORTED); case RILConstants.OP_NOT_ALLOWED_DURING_VOICE_CALL: return new CommandException(Error.OP_NOT_ALLOWED_DURING_VOICE_CALL); @@ -75,8 +74,7 @@ public class CommandException extends RuntimeException } } - public Error getCommandError() - { + public Error getCommandError() { return e; } diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java similarity index 68% rename from telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java rename to telephony/java/com/android/internal/telephony/CommandsInterface.java index 791579835cde9e1dbacd4bd197bc71390f34921e..5a1bb7e72fc76b005f71910eb2e6b0395b0e2233 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -14,50 +14,79 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; +package com.android.internal.telephony; + import android.os.Message; import android.os.Handler; + /** * {@hide} */ -public interface CommandsInterface -{ +public interface CommandsInterface { enum RadioState { RADIO_OFF, /* Radio explictly powered off (eg CFUN=0) */ RADIO_UNAVAILABLE, /* Radio unavailable (eg, resetting or not booted) */ SIM_NOT_READY, /* Radio is on, but the SIM interface is not ready */ - SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network + SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network personalization, or SIM absent */ - SIM_READY; /* Radio is on and SIM interface is available */ - - boolean isOn() /* and available...*/ - { + SIM_READY, /* Radio is on and SIM interface is available */ + RUIM_NOT_READY, /* Radio is on, but the RUIM interface is not ready */ + RUIM_READY, /* Radio is on and the RUIM interface is available */ + RUIM_LOCKED_OR_ABSENT, /* RUIM PIN locked, PUK required, network + personalization locked, or RUIM absent */ + NV_NOT_READY, /* Radio is on, but the NV interface is not available */ + NV_READY; /* Radio is on and the NV interface is available */ + + public boolean isOn() /* and available...*/ { return this == SIM_NOT_READY || this == SIM_LOCKED_OR_ABSENT - || this == SIM_READY; + || this == SIM_READY + || this == RUIM_NOT_READY + || this == RUIM_READY + || this == RUIM_LOCKED_OR_ABSENT + || this == NV_NOT_READY + || this == NV_READY; } - boolean isAvailable() - { + public boolean isAvailable() { return this != RADIO_UNAVAILABLE; } - boolean isSIMReady() - { - // if you add new states after SIM_READY, include them too + public boolean isSIMReady() { return this == SIM_READY; } + + public boolean isRUIMReady() { + return this == RUIM_READY; + } + + public boolean isNVReady() { + return this == NV_READY; + } + + public boolean isGsm() { + return this == SIM_NOT_READY + || this == SIM_LOCKED_OR_ABSENT + || this == SIM_READY; + } + + public boolean isCdma() { + return this == RUIM_NOT_READY + || this == RUIM_READY + || this == RUIM_LOCKED_OR_ABSENT + || this == NV_NOT_READY + || this == NV_READY; + } } - enum SimStatus { - SIM_ABSENT, - SIM_NOT_READY, - SIM_READY, - SIM_PIN, - SIM_PUK, - SIM_NETWORK_PERSONALIZATION + enum IccStatus { + ICC_ABSENT, + ICC_NOT_READY, + ICC_READY, + ICC_PIN, + ICC_PUK, + ICC_NETWORK_PERSONALIZATION } //***** Constants @@ -93,7 +122,7 @@ public interface CommandsInterface static final String CB_FACILITY_BA_MT = "AC"; static final String CB_FACILITY_BA_SIM = "SC"; static final String CB_FACILITY_BA_FD = "FD"; - + // Used for various supp services apis // See 27.007 +CCFC or +CLCK @@ -102,7 +131,7 @@ public interface CommandsInterface static final int SERVICE_CLASS_DATA = (1 << 1); //synoym for 16+32+64+128 static final int SERVICE_CLASS_FAX = (1 << 2); static final int SERVICE_CLASS_SMS = (1 << 3); - static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); + static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); static final int SERVICE_CLASS_DATA_ASYNC = (1 << 5); static final int SERVICE_CLASS_PACKET = (1 << 6); static final int SERVICE_CLASS_PAD = (1 << 7); @@ -122,8 +151,8 @@ public interface CommandsInterface RadioState getRadioState(); - /** - * Fires on any RadioState transition + /** + * Fires on any RadioState transition * Always fires immediately as well * * do not attempt to calculate transitions by storing getRadioState() values @@ -131,58 +160,85 @@ public interface CommandsInterface * registration methods */ void registerForRadioStateChanged(Handler h, int what, Object obj); + void unregisterForRadioStateChanged(Handler h); - /** - * Fires on any transition into RadioState.isOn() + /** + * Fires on any transition into RadioState.isOn() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForOn(Handler h, int what, Object obj); + void unregisterForOn(Handler h); - /** - * Fires on any transition out of RadioState.isAvailable() + /** + * Fires on any transition out of RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForAvailable(Handler h, int what, Object obj); - //void unregisterForAvailable(Handler h); - /** + void unregisterForAvailable(Handler h); + + /** * Fires on any transition into !RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForNotAvailable(Handler h, int what, Object obj); - //void unregisterForNotAvailable(Handler h); - /** + void unregisterForNotAvailable(Handler h); + + /** * Fires on any transition into RADIO_OFF or !RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForOffOrNotAvailable(Handler h, int what, Object obj); - //void unregisterForNotAvailable(Handler h); + void unregisterForOffOrNotAvailable(Handler h); - /** + /** * Fires on any transition into SIM_READY * Fires immediately if if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForSIMReady(Handler h, int what, Object obj); - //void unregisterForSIMReady(Handler h); + void unregisterForSIMReady(Handler h); + /** Any transition into SIM_LOCKED_OR_ABSENT */ void registerForSIMLockedOrAbsent(Handler h, int what, Object obj); - //void unregisterForSIMLockedOrAbsent(Handler h); + void unregisterForSIMLockedOrAbsent(Handler h); void registerForCallStateChanged(Handler h, int what, Object obj); - //void unregisterForCallStateChanged(Handler h); + void unregisterForCallStateChanged(Handler h); void registerForNetworkStateChanged(Handler h, int what, Object obj); - //void unregisterForNetworkStateChanged(Handler h); - void registerForPDPStateChanged(Handler h, int what, Object obj); - //void unregisterForPDPStateChanged(Handler h); + void unregisterForNetworkStateChanged(Handler h); + void registerForDataStateChanged(Handler h, int what, Object obj); + void unregisterForDataStateChanged(Handler h); + + void registerForRadioTechnologyChanged(Handler h, int what, Object obj); + void unregisterForRadioTechnologyChanged(Handler h); + void registerForNVReady(Handler h, int what, Object obj); + void unregisterForNVReady(Handler h); + void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj); + void unregisterForRUIMLockedOrAbsent(Handler h); + + /** InCall voice privacy notifications */ + void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj); + void unregisterForInCallVoicePrivacyOn(Handler h); + void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj); + void unregisterForInCallVoicePrivacyOff(Handler h); + + /** + * Fires on any transition into RUIM_READY + * Fires immediately if if currently in that state + * In general, actions should be idempotent. State may change + * before event is received. + */ + void registerForRUIMReady(Handler h, int what, Object obj); + void unregisterForRUIMReady(Handler h); /** * unlike the register* methods, there's only one new SMS handler @@ -192,21 +248,24 @@ public interface CommandsInterface * AsyncResult.result is a String containing the SMS PDU */ void setOnNewSMS(Handler h, int what, Object obj); + void unSetOnNewSMS(Handler h); /** - * Register for NEW_SMS_ON_SIM unsolicited message + * Register for NEW_SMS_ON_SIM unsolicited message * * AsyncResult.result is an int array containing the index of new SMS */ void setOnSmsOnSim(Handler h, int what, Object obj); + void unSetOnSmsOnSim(Handler h); /** - * Register for NEW_SMS_STATUS_REPORT unsolicited message + * Register for NEW_SMS_STATUS_REPORT unsolicited message * * AsyncResult.result is a String containing the status report PDU */ void setOnSmsStatus(Handler h, int what, Object obj); - + void unSetOnSmsStatus(Handler h); + /** * unlike the register* methods, there's only one NITZ time handler * @@ -220,13 +279,14 @@ public interface CommandsInterface * seconds on system startup */ void setOnNITZTime(Handler h, int what, Object obj); + void unSetOnNITZTime(Handler h); /** * unlike the register* methods, there's only one USSD notify handler * * Represents the arrival of a USSD "notify" message, which may * or may not have been triggered by a previous USSD send - * + * * AsyncResult.result is a String[] * ((String[])(AsyncResult.result))[0] contains status code * "0" USSD-Notify -- text in ((const char **)data)[1] @@ -241,26 +301,29 @@ public interface CommandsInterface */ void setOnUSSD(Handler h, int what, Object obj); + void unSetOnUSSD(Handler h); /** * unlike the register* methods, there's only one signal strength handler - * AsyncResult.result is an int[2] - * response.obj.result[0] is received signal strength (0-31, 99) - * response.obj.result[1] is bit error rate (0-7, 99) + * AsyncResult.result is an int[2] + * response.obj.result[0] is received signal strength (0-31, 99) + * response.obj.result[1] is bit error rate (0-7, 99) * as defined in TS 27.007 8.5 */ void setOnSignalStrengthUpdate(Handler h, int what, Object obj); + void unSetOnSignalStrengthUpdate(Handler h); /** - * Sets the handler for SIM SMS storage full unsolicited message. + * Sets the handler for SIM/RUIM SMS storage full unsolicited message. * Unlike the register* methods, there's only one notification handler * * @param h Handler for notification message. * @param what User-defined message code. * @param obj User object. */ - void setOnSimSmsFull(Handler h, int what, Object obj); + void setOnIccSmsFull(Handler h, int what, Object obj); + void unSetOnIccSmsFull(Handler h); /** * Sets the handler for SIM Refresh notifications. @@ -270,8 +333,9 @@ public interface CommandsInterface * @param what User-defined message code. * @param obj User object. */ - void setOnSimRefresh(Handler h, int what, Object obj); - + void setOnIccRefresh(Handler h, int what, Object obj); + void unSetOnIccRefresh(Handler h); + /** * Sets the handler for RING notifications. * Unlike the register* methods, there's only one notification handler @@ -281,7 +345,8 @@ public interface CommandsInterface * @param obj User object. */ void setOnCallRing(Handler h, int what, Object obj); - + void unSetOnCallRing(Handler h); + /** * Sets the handler for RESTRICTED_STATE changed notification, * eg, for Domain Specific Access Control @@ -292,7 +357,8 @@ public interface CommandsInterface */ void setOnRestrictedStateChanged(Handler h, int what, Object obj); - + void unSetOnRestrictedStateChanged(Handler h); + /** * Sets the handler for Supplementary Service Notifications. * Unlike the register* methods, there's only one notification handler @@ -302,6 +368,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnSuppServiceNotification(Handler h, int what, Object obj); + void unSetOnSuppServiceNotification(Handler h); /** * Sets the handler for Session End Notifications for STK. @@ -312,6 +379,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkSessionEnd(Handler h, int what, Object obj); + void unSetOnStkSessionEnd(Handler h); /** * Sets the handler for Proactive Commands for STK. @@ -322,6 +390,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkProactiveCmd(Handler h, int what, Object obj); + void unSetOnStkProactiveCmd(Handler h); /** * Sets the handler for Event Notifications for STK. @@ -332,6 +401,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkEvent(Handler h, int what, Object obj); + void unSetOnStkEvent(Handler h); /** * Sets the handler for Call Set Up Notifications for STK. @@ -342,6 +412,7 @@ public interface CommandsInterface * @param obj User object. */ void setOnStkCallSetUp(Handler h, int what, Object obj); + void unSetOnStkCallSetUp(Handler h); /** * Enables/disbables supplementary service related notifications from @@ -351,19 +422,21 @@ public interface CommandsInterface * @param result Message to be posted when command completes. */ void setSuppServiceNotifications(boolean enable, Message result); + //void unSetSuppServiceNotifications(Handler h); + /** - * Returns current SIM status. + * Returns current ICC status. + * + * AsyncResult.result is IccStatus * - * AsyncResult.result is SimStatus - * */ - void getSimStatus(Message result); + void getIccStatus(Message result); /** - * Supply the SIM PIN to the SIM card - * + * Supply the ICC PIN to the ICC card + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -373,11 +446,11 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPin(String pin, Message result); + void supplyIccPin(String pin, Message result); /** - * Supply the SIM PUK to the SIM card - * + * Supply the ICC PUK to the ICC card + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -387,13 +460,13 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPuk(String puk, String newPin, Message result); + void supplyIccPuk(String puk, String newPin, Message result); /** - * Supply the SIM PIN2 to the SIM card - * Only called following operation where SIM_PIN2 was + * Supply the ICC PIN2 to the ICC card + * Only called following operation where ICC_PIN2 was * returned as a a failure from a previous operation - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -403,13 +476,13 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPin2(String pin2, Message result); + void supplyIccPin2(String pin2, Message result); /** * Supply the SIM PUK2 to the SIM card * Only called following operation where SIM_PUK2 was * returned as a a failure from a previous operation - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -419,16 +492,16 @@ public interface CommandsInterface * ar.exception and ar.result are null on success */ - void supplySimPuk2(String puk2, String newPin2, Message result); + void supplyIccPuk2(String puk2, String newPin2, Message result); - void changeSimPin(String oldPin, String newPin, Message result); - void changeSimPin2(String oldPin2, String newPin2, Message result); + void changeIccPin(String oldPin, String newPin, Message result); + void changeIccPin2(String oldPin2, String newPin2, Message result); void changeBarringPassword(String facility, String oldPwd, String newPwd, Message result); void supplyNetworkDepersonalization(String netpin, Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -438,16 +511,26 @@ public interface CommandsInterface */ void getCurrentCalls (Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result contains a List of PDPContextState + * @deprecated */ void getPDPContextList(Message result); - /** + /** + * returned message + * retMsg.obj = AsyncResult ar + * ar.exception carries exception on failure + * ar.userObject contains the orignal value of result.obj + * ar.result contains a List of PDPContextState + */ + void getDataCallList(Message result); + + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -460,7 +543,7 @@ public interface CommandsInterface */ void dial (String address, int clirMode, Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -469,7 +552,7 @@ public interface CommandsInterface */ void getIMSI(Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -478,7 +561,7 @@ public interface CommandsInterface */ void getIMEI(Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -487,7 +570,7 @@ public interface CommandsInterface */ void getIMEISV(Message result); - /** + /** * Hang up one individual connection. * returned message * retMsg.obj = AsyncResult ar @@ -512,7 +595,7 @@ public interface CommandsInterface /** * 3GPP 22.030 6.5.5 - * "Releases all active calls (if any exist) and accepts + * "Releases all active calls (if any exist) and accepts * the other (held or waiting) call." * * ar.exception carries exception on failure @@ -523,7 +606,7 @@ public interface CommandsInterface /** * 3GPP 22.030 6.5.5 - * "Places all active calls (if any exist) on hold and accepts + * "Places all active calls (if any exist) on hold and accepts * the other (held or waiting) call." * * ar.exception carries exception on failure @@ -539,12 +622,27 @@ public interface CommandsInterface * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void conference (Message result); + /** + * Set preferred Voice Privacy (VP). + * + * @param enable true is enhanced and false is normal VP + * @param result is a callback message + */ + void setPreferredVoicePrivacy(boolean enable, Message result); + + /** + * Get currently set preferred Voice Privacy (VP) mode. + * + * @param result is a callback message + */ + void getPreferredVoicePrivacy(Message result); + /** * 3GPP 22.030 6.5.5 - * "Places all active calls on hold except call X with which + * "Places all active calls on hold except call X with which * communication shall be supported." */ void separateConnection (int gsmIndex, Message result); @@ -554,15 +652,15 @@ public interface CommandsInterface * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void acceptCall (Message result); - /** + /** * also known as UDUB * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void rejectCall (Message result); /** @@ -586,14 +684,21 @@ public interface CommandsInterface void getLastCallFailCause (Message result); - /** + /** * Reason for last PDP context deactivate or failure to activate * cause code returned as int[0] in Message.obj.response * returns an integer cause code defined in TS 24.008 * section 6.1.3.1.3 or close approximation + * @deprecated */ void getLastPdpFailCause (Message result); + /** + * The preferred new alternative to getLastPdpFailCause + * that is also CDMA-compatible. + */ + void getLastDataCallFailCause (Message result); + void setMute (boolean enableMute, Message response); void getMute (Message response); @@ -601,8 +706,8 @@ public interface CommandsInterface /** * response.obj is an AsyncResult * response.obj.result is an int[2] - * response.obj.result[0] is received signal strength (0-31, 99) - * response.obj.result[1] is bit error rate (0-7, 99) + * response.obj.result[0] is received signal strength (0-31, 99) + * response.obj.result[1] is bit error rate (0-7, 99) * as defined in TS 27.007 8.5 */ void getSignalStrength (Message response); @@ -612,21 +717,21 @@ public interface CommandsInterface * response.obj.result is an int[3] * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2 * response.obj.result[1] is LAC if registered or -1 if not - * response.obj.result[2] is CID if registered or -1 if not + * response.obj.result[2] is CID if registered or -1 if not * valid LAC and CIDs are 0x0000 - 0xffff - * + * * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ void getRegistrationState (Message response); - + /** * response.obj.result is an int[3] * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2 * response.obj.result[1] is LAC if registered or -1 if not - * response.obj.result[2] is CID if registered or -1 if not + * response.obj.result[2] is CID if registered or -1 if not * valid LAC and CIDs are 0x0000 - 0xffff - * + * * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ @@ -637,14 +742,14 @@ public interface CommandsInterface * response.obj.result[0] is long alpha or null if unregistered * response.obj.result[1] is short alpha or null if unregistered * response.obj.result[2] is numeric or null if unregistered - */ + */ void getOperator(Message response); /** * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void sendDtmf(char c, Message result); @@ -667,26 +772,40 @@ public interface CommandsInterface * smscPDU is smsc address in PDU form GSM BCD format prefixed * by a length byte (as expected by TS 27.005) or NULL for default SMSC * pdu is SMS in PDU format as an ASCII hex string - * less the SMSC address + * less the SMSC address */ void sendSMS (String smscPDU, String pdu, Message response); + /** + * @param pdu is CDMA-SMS in internal pseudo-PDU format + * @param response sent when operation completes + */ + void sendCdmaSms(byte[] pdu, Message response); + /** * Deletes the specified SMS record from SIM memory (EF_SMS). - * + * * @param index index of the SMS record to delete * @param response sent when operation completes */ void deleteSmsOnSim(int index, Message response); + /** + * Deletes the specified SMS record from RUIM memory (EF_SMS in DF_CDMA). + * + * @param index index of the SMS record to delete + * @param response sent when operation completes + */ + void deleteSmsOnRuim(int index, Message response); + /** * Writes an SMS message to SIM memory (EF_SMS). - * + * * @param status status of message on SIM. One of: - * SmsManger.STATUS_ON_SIM_READ - * SmsManger.STATUS_ON_SIM_UNREAD - * SmsManger.STATUS_ON_SIM_SENT - * SmsManger.STATUS_ON_SIM_UNSENT + * SmsManger.STATUS_ON_ICC_READ + * SmsManger.STATUS_ON_ICC_UNREAD + * SmsManger.STATUS_ON_ICC_SENT + * SmsManger.STATUS_ON_ICC_UNSENT * @param pdu message PDU, as hex string * @param response sent when operation completes. * response.obj will be an AsyncResult, and will indicate @@ -694,89 +813,105 @@ public interface CommandsInterface */ void writeSmsToSim(int status, String smsc, String pdu, Message response); + void writeSmsToRuim(int status, String pdu, Message response); + + /** + * @deprecated + * @param apn + * @param user + * @param password + * @param response + */ void setupDefaultPDP(String apn, String user, String password, Message response); + /** + * @deprecated + * @param cid + * @param response + */ void deactivateDefaultPDP(int cid, Message response); void setRadioPower(boolean on, Message response); void acknowledgeLastIncomingSMS(boolean success, Message response); - /** - * parameters equivilient to 27.007 AT+CRSM command + void acknowledgeLastIncomingCdmaSms(boolean success, Message response); + + /** + * parameters equivilient to 27.007 AT+CRSM command * response.obj will be an AsyncResult - * response.obj.userObj will be a SimIoResult on success + * response.obj.userObj will be a IccIoResult on success */ - void simIO (int command, int fileid, String path, int p1, int p2, int p3, + void iccIO (int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, Message response); /** * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned". + * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned". * * @param response is callback message */ - + void queryCLIP(Message response); /** * response.obj will be a an int[2] * * response.obj[0] will be TS 27.007 +CLIR parameter 'n' - * 0 presentation indicator is used according to the subscription of the CLIR service - * 1 CLIR invocation - * 2 CLIR suppression + * 0 presentation indicator is used according to the subscription of the CLIR service + * 1 CLIR invocation + * 2 CLIR suppression * * response.obj[1] will be TS 27.007 +CLIR parameter 'm' - * 0 CLIR not provisioned - * 1 CLIR provisioned in permanent mode - * 2 unknown (e.g. no network, etc.) - * 3 CLIR temporary mode presentation restricted - * 4 CLIR temporary mode presentation allowed + * 0 CLIR not provisioned + * 1 CLIR provisioned in permanent mode + * 2 unknown (e.g. no network, etc.) + * 3 CLIR temporary mode presentation restricted + * 4 CLIR temporary mode presentation allowed */ void getCLIR(Message response); - + /** * clirMode is one of the CLIR_* constants above * * response.obj is null */ - + void setCLIR(int clirMode, Message response); /** * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 0 for disabled, 1 for enabled. + * 0 for disabled, 1 for enabled. * * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void queryCallWaiting(int serviceClass, Message response); - + /** * @param enable is true to enable, false to disable * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void setCallWaiting(boolean enable, int serviceClass, Message response); /** * @param action is one of CF_ACTION_* * @param cfReason is one of CF_REASON_* - * @param serviceClass is a sum of SERVICE_CLASSS_* + * @param serviceClass is a sum of SERVICE_CLASSS_* */ - void setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message response); + void setCallForward(int action, int cfReason, int serviceClass, + String number, int timeSeconds, Message response); /** * cfReason is one of CF_REASON_* * * ((AsyncResult)response.obj).result will be an array of * CallForwardInfo's - * + * * An array of length 0 means "disabled for all codes" */ void queryCallForwardStatus(int cfReason, int serviceClass, @@ -815,7 +950,7 @@ public interface CommandsInterface * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void queryFacilityLock (String facility, String password, int serviceClass, Message response); @@ -828,7 +963,7 @@ public interface CommandsInterface */ void setFacilityLock (String facility, boolean lockState, String password, int serviceClass, Message response); - + void sendUSSD (String ussdString, Message response); @@ -850,7 +985,7 @@ public interface CommandsInterface /** * Query the list of band mode supported by RF. - * + * * @param response is callback message * ((AsyncResult)response.obj).result is an int[] with every * element representing one avialable BM_*_BAND @@ -888,6 +1023,21 @@ public interface CommandsInterface */ void setLocationUpdates(boolean enable, Message response); + /** + * Gets the default SMSC address. + * + * @param result Callback message contains the SMSC address. + */ + void getSmscAddress(Message result); + + /** + * Sets the default SMSC address. + * + * @param address new SMSC address + * @param result Callback message is empty on completion + */ + void setSmscAddress(String address, Message result); + void invokeOemRilRequestRaw(byte[] data, Message response); @@ -923,4 +1073,136 @@ public interface CommandsInterface * @param response Callback message */ public void handleCallSetupRequestFromSim(boolean accept, Message response); + + //***** new Methods for CDMA support + + /** + * Request the device ESN / MEID / IMEI / IMEISV. + * "response" is const char ** + * [0] is IMEI if GSM subscription is available + * [1] is IMEISV if GSM subscription is available + * [2] is ESN if CDMA subscription is available + * [3] is MEID if CDMA subscription is available + */ + public void getDeviceIdentity(Message response); + + /** + * Request the device IMSI_M / MDN / AH_SID / H_SID / H_NID. + * "response" is const char ** + * [0] is IMSI_M if CDMA subscription is available + * [1] is MDN if CDMA subscription is available + * [2] is AH_SID (Analog Home SID) if CDMA subscription + * [3] is H_SID (Home SID) if CDMA subscription is available + * [4] is H_NID (Home SID) if CDMA subscription is available + */ + public void getCDMASubscription(Message response); + + /** + * Send Flash Code. + * "response" is is NULL + * [0] is a FLASH string + */ + public void sendCDMAFeatureCode(String FeatureCode, Message response); + + /** Set the Phone type created */ + void setPhoneType(int phoneType); + /** + * Query the CDMA roaming preference setting + * + * @param response is callback message to report one of CDMA_RM_* + */ + void queryCdmaRoamingPreference(Message response); + + /** + * Requests to set the CDMA roaming preference + * @param cdmaRoamingType one of CDMA_RM_* + * @param response is callback message + */ + void setCdmaRoamingPreference(int cdmaRoamingType, Message response); + + /** + * Requests to set the CDMA subscription mode + * @param cdmaSubscriptionType one of CDMA_SUBSCRIPTION_* + * @param response is callback message + */ + void setCdmaSubscription(int cdmaSubscriptionType, Message response); + + /** + * Set the TTY mode for the CDMA phone + * + * @param enable is true to enable, false to disable + * @param response is callback message + */ + void setTTYModeEnabled(boolean enable, Message response); + + /** + * Query the TTY mode for the CDMA phone + * (AsyncResult)response.obj).result is an int[] with element [0] set to + * 0 for disabled, 1 for enabled. + * + * @param response is callback message + */ + void queryTTYModeEnabled(Message response); + + /** + * Setup a packet data connection On successful completion, the result + * message will return the following: [0] indicating PDP CID, which is + * generated by RIL. This Connection ID is used in both GSM/UMTS and CDMA + * modes [1] indicating the network interface name for GSM/UMTS or CDMA [2] + * indicating the IP address for this interface for GSM/UMTS and NULL in the + * case of CDMA + * + * @param radioTechnology + * indicates whether to setup connection on radio technology CDMA + * (0) or GSM/UMTS (1) + * @param profile + * Profile Number or NULL to indicate default profile + * @param apn + * the APN to connect to if radio technology is GSM/UMTS. + * Otherwise null for CDMA. + * @param user + * the username for APN, or NULL + * @param password + * the password for APN, or NULL + * @param result + * Callback message + */ + public void setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, Message result); + + /** + * Deactivate packet data connection + * + * @param cid + * The connection ID + * @param result + * Callback message is empty on completion + */ + public void deactivateDataCall(int cid, Message result); + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param result + * Callback message is empty on completion + */ + public void activateCdmaBroadcastSms(int activate, Message result); + + /** + * Configure cdma cell broadcast SMS. + * + * @param result + * Callback message is empty on completion + */ + public void setCdmaBroadcastConfig(int[] configValuesArray, Message result); + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param result + * Callback message contains the configuration from the modem on completion + */ + public void getCdmaBroadcastConfig(Message result); } diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index ead49bfbe4f6c086f2531cb88ec2261f7a35e526..86ceb89ee5bdf749418454e27634d39b22da0bd6 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -19,8 +19,8 @@ package com.android.internal.telephony; /** * {@hide} */ -public abstract class Connection -{ +public abstract class Connection { + // Number presentation type for caller id display public static int PRESENTATION_ALLOWED = 1; // normal public static int PRESENTATION_RESTRICTED = 2; // block by user @@ -42,7 +42,7 @@ public abstract class Connection INCOMING_REJECTED, /* an incoming call that was rejected */ POWER_OFF, /* radio is turned off explicitly */ OUT_OF_SERVICE, /* out of service */ - SIM_ERROR, /* No SIM, SIM locked, or other SIM error */ + ICC_ERROR, /* No ICC, ICC locked, or other ICC error */ CALL_BARRED, /* call was blocked by call barrring */ FDN_BLOCKED, /* call was blocked by fixed dial number */ CS_RESTRICTED, /* call was blocked by restricted all voice access */ @@ -54,7 +54,7 @@ public abstract class Connection /* Instance Methods */ - /** + /** * Gets address (e.g., phone number) associated with connection * TODO: distinguish reasons for unavailablity * @@ -92,7 +92,7 @@ public abstract class Connection public abstract long getDisconnectTime(); /** - * returns the number of milliseconds the call has been connected, + * returns the number of milliseconds the call has been connected, * or 0 if the call has never connected. * If the call is still connected, then returns the elapsed * time since connect @@ -113,8 +113,8 @@ public abstract class Connection public abstract DisconnectCause getDisconnectCause(); /** - * Returns true of this connection originated elsewhere - * ("MT" or mobile terminated; another party called this terminal) + * Returns true of this connection originated elsewhere + * ("MT" or mobile terminated; another party called this terminal) * or false if this call originated here (MO or mobile originated) */ public abstract boolean isIncoming(); @@ -122,32 +122,30 @@ public abstract class Connection /** * If this Connection is connected, then it is associated with * a Call. - * + * * Returns getCall().getState() or Call.State.IDLE if not * connected */ - public Call.State getState() - { + public Call.State getState() { Call c; c = getCall(); - if (c == null) { + if (c == null) { return Call.State.IDLE; } else { return c.getState(); } } - + /** * isAlive() - * + * * @return true if the connection isn't disconnected * (could be active, holding, ringing, dialing, etc) */ public boolean - isAlive() - { + isAlive() { return getState().isAlive(); } @@ -155,29 +153,26 @@ public abstract class Connection * Returns true if Connection is connected and is INCOMING or WAITING */ public boolean - isRinging() - { + isRinging() { return getState().isRinging(); } /** - * + * * @return the userdata set in setUserData() */ - public Object getUserData() - { + public Object getUserData() { return userData; } /** - * + * * @param userdata user can store an any userdata in the Connection object. */ - public void setUserData(Object userdata) - { + public void setUserData(Object userdata) { this.userData = userdata; } - + /** * Hangup individual Connection */ @@ -191,16 +186,16 @@ public abstract class Connection public abstract void separate() throws CallStateException; public enum PostDialState { - NOT_STARTED, /* The post dial string playback hasn't - been started, or this call is not yet + NOT_STARTED, /* The post dial string playback hasn't + been started, or this call is not yet connected, or this is an incoming call */ STARTED, /* The post dial string playback has begun */ - WAIT, /* The post dial string playback is waiting for a + WAIT, /* The post dial string playback is waiting for a call to proceedAfterWaitChar() */ - WILD, /* The post dial string playback is waiting for a + WILD, /* The post dial string playback is waiting for a call to proceedAfterWildChar() */ COMPLETE, /* The post dial string playback is complete */ - CANCELLED /* The post dial string playback was cancelled + CANCELLED /* The post dial string playback was cancelled with cancelPostDial() */ } @@ -215,7 +210,7 @@ public abstract class Connection /** * See Phone.setOnPostDialWaitCharacter() */ - + public abstract void proceedAfterWaitChar(); /** @@ -232,5 +227,5 @@ public abstract class Connection * @return one of PRESENTATION_* */ public abstract int getNumberPresentation(); - + } diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..6e9d1abeb8e48630d098500608d56fcd23811931 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -0,0 +1,299 @@ +/* + * 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.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +/** + * {@hide} + */ +public abstract class DataConnection extends Handler { + + // the inherited class + + public enum State { + ACTIVE, /* has active data connection */ + ACTIVATING, /* during connecting process */ + INACTIVE; /* has empty data connection */ + + public String toString() { + switch (this) { + case ACTIVE: + return "active"; + case ACTIVATING: + return "setting up"; + default: + return "inactive"; + } + } + + public boolean isActive() { + return this == ACTIVE; + } + + public boolean isInactive() { + return this == INACTIVE; + } + } + + public enum FailCause { + NONE, + BAD_APN, + BAD_PAP_SECRET, + BARRED, + USER_AUTHENTICATION, + SERVICE_OPTION_NOT_SUPPORTED, + SERVICE_OPTION_NOT_SUBSCRIBED, + SIM_LOCKED, + RADIO_OFF, + NO_SIGNAL, + NO_DATA_PLAN, + RADIO_NOT_AVAILABLE, + SUSPENED_TEMPORARY, + RADIO_ERROR_RETRY, + UNKNOWN; + + public boolean isPermanentFail() { + return (this == RADIO_OFF); + } + + public String toString() { + switch (this) { + case NONE: + return "no error"; + case BAD_APN: + return "bad apn"; + case BAD_PAP_SECRET: + return "bad pap secret"; + case BARRED: + return "barred"; + case USER_AUTHENTICATION: + return "error user autentication"; + case SERVICE_OPTION_NOT_SUPPORTED: + return "data not supported"; + case SERVICE_OPTION_NOT_SUBSCRIBED: + return "datt not subcribed"; + case SIM_LOCKED: + return "sim locked"; + case RADIO_OFF: + return "radio is off"; + case NO_SIGNAL: + return "no signal"; + case NO_DATA_PLAN: + return "no data plan"; + case RADIO_NOT_AVAILABLE: + return "radio not available"; + case SUSPENED_TEMPORARY: + return "suspend temporary"; + case RADIO_ERROR_RETRY: + return "transient radio error"; + default: + return "unknown data error"; + } + } + } + + // ***** Event codes + protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1; + protected static final int EVENT_GET_LAST_FAIL_DONE = 2; + protected static final int EVENT_LINK_STATE_CHANGED = 3; + protected static final int EVENT_DEACTIVATE_DONE = 4; + protected static final int EVENT_FORCE_RETRY = 5; + + //***** Tag IDs for EventLog + protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; + + + //***** Member Variables + protected PhoneBase phone; + protected Message onConnectCompleted; + protected Message onDisconnect; + protected int cid; + protected String interfaceName; + protected String ipAddress; + protected String gatewayAddress; + protected String[] dnsServers; + protected State state; + protected long createTime; + protected long lastFailTime; + protected FailCause lastFailCause; + protected static final String NULL_IP = "0.0.0.0"; + Object userData; + + // receivedDisconnectReq is set when disconnect during activation + protected boolean receivedDisconnectReq; + + /* Instance Methods */ + protected abstract void onSetupConnectionCompleted(AsyncResult ar); + + protected abstract void onDeactivated(AsyncResult ar); + + protected abstract void disconnect(Message msg); + + protected abstract void notifyFail(FailCause cause, Message onCompleted); + + protected abstract void notifyDisconnect(Message msg); + + protected abstract void onLinkStateChanged(DataLink.LinkState linkState); + + protected abstract FailCause getFailCauseFromRequest(int rilCause); + + public abstract String toString(); + + protected abstract void log(String s); + + + //***** Constructor + protected DataConnection(PhoneBase phone) { + super(); + this.phone = phone; + onConnectCompleted = null; + onDisconnect = null; + this.cid = -1; + receivedDisconnectReq = false; + this.dnsServers = new String[2]; + + clearSettings(); + } + + protected void setHttpProxy(String httpProxy, String httpPort) { + if (httpProxy == null || httpProxy.length() == 0) { + phone.setSystemProperty("net.gprs.http-proxy", null); + return; + } + + if (httpPort == null || httpPort.length() == 0) { + httpPort = "8080"; // Default to port 8080 + } + + phone.setSystemProperty("net.gprs.http-proxy", + "http://" + httpProxy + ":" + httpPort + "/"); + } + + public String getInterface() { + return interfaceName; + } + + public String getIpAddress() { + return ipAddress; + } + + public String getGatewayAddress() { + return gatewayAddress; + } + + public String[] getDnsServers() { + return dnsServers; + } + + public void clearSettings() { + log("DataConnection.clearSettings()"); + + this.state = State.INACTIVE; + this.createTime = -1; + this.lastFailTime = -1; + this.lastFailCause = FailCause.NONE; + + receivedDisconnectReq = false; + onConnectCompleted = null; + interfaceName = null; + ipAddress = null; + gatewayAddress = null; + dnsServers[0] = null; + dnsServers[1] = null; + } + + protected void onGetLastFailCompleted(AsyncResult ar) { + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + FailCause cause = FailCause.UNKNOWN; + + if (ar.exception == null) { + int rilFailCause = ((int[]) (ar.result))[0]; + cause = getFailCauseFromRequest(rilFailCause); + } + notifyFail(cause, onConnectCompleted); + } + } + + protected void onForceRetry() { + if (receivedDisconnectReq) { + notifyDisconnect(onDisconnect); + } else { + notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted); + } + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + log("DataConnection.handleMessage()"); + + switch (msg.what) { + + case EVENT_SETUP_DATA_CONNECTION_DONE: + onSetupConnectionCompleted((AsyncResult) msg.obj); + break; + + case EVENT_FORCE_RETRY: + onForceRetry(); + break; + + case EVENT_GET_LAST_FAIL_DONE: + onGetLastFailCompleted((AsyncResult) msg.obj); + break; + + case EVENT_LINK_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + DataLink.LinkState ls = (DataLink.LinkState) ar.result; + onLinkStateChanged(ls); + break; + + case EVENT_DEACTIVATE_DONE: + onDeactivated((AsyncResult) msg.obj); + break; + } + } + + public State getState() { + log("DataConnection.getState()"); + return state; + } + + public long getConnectionTime() { + log("DataConnection.getConnectionTime()"); + return createTime; + } + + public long getLastFailTime() { + log("DataConnection.getLastFailTime()"); + return lastFailTime; + } + + public FailCause getLastFailCause() { + log("DataConnection.getLastFailCause()"); + return lastFailCause; + } +} diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java new file mode 100644 index 0000000000000000000000000000000000000000..5b826b2d4a7146e0af8cf3e08e393059887473f7 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -0,0 +1,313 @@ +/* + * 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.app.PendingIntent; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.INetStatService; +import android.os.Message; +import android.os.RemoteException; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.util.Log; + +/** + * {@hide} + * + */ +public abstract class DataConnectionTracker extends Handler { + private static final boolean DBG = true; + + /** + * IDLE: ready to start data connection setup, default state + * INITING: state of issued setupDefaultPDP() but not finish yet + * CONNECTING: state of issued startPppd() but not finish yet + * 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: Connection.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 or DISCONNECTING + */ + public enum State { + IDLE, + INITING, + CONNECTING, + SCANNING, + CONNECTED, + DISCONNECTING, + FAILED + } + + public enum Activity { + NONE, + DATAIN, + DATAOUT, + DATAINANDOUT + } + + //***** Event Codes + protected static final int EVENT_DATA_SETUP_COMPLETE = 1; + protected static final int EVENT_RADIO_AVAILABLE = 3; + protected static final int EVENT_RECORDS_LOADED = 4; + protected static final int EVENT_TRY_SETUP_DATA = 5; + protected static final int EVENT_DATA_STATE_CHANGED = 6; + protected static final int EVENT_POLL_PDP = 7; + protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11; + protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12; + protected static final int EVENT_VOICE_CALL_STARTED = 14; + protected static final int EVENT_VOICE_CALL_ENDED = 15; + protected static final int EVENT_GPRS_DETACHED = 19; + protected static final int EVENT_LINK_STATE_CHANGED = 20; + protected static final int EVENT_ROAMING_ON = 21; + protected static final int EVENT_ROAMING_OFF = 22; + protected static final int EVENT_ENABLE_NEW_APN = 23; + protected static final int EVENT_RESTORE_DEFAULT_APN = 24; + protected static final int EVENT_DISCONNECT_DONE = 25; + protected static final int EVENT_GPRS_ATTACHED = 26; + protected static final int EVENT_START_NETSTAT_POLL = 27; + protected static final int EVENT_START_RECOVERY = 28; + protected static final int EVENT_APN_CHANGED = 29; + protected static final int EVENT_CDMA_DATA_DETACHED = 30; + protected static final int EVENT_NV_READY = 31; + protected static final int EVENT_PS_RESTRICT_ENABLED = 32; + protected static final int EVENT_PS_RESTRICT_DISABLED = 33; + + //***** Constants + protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; + + /** Cap out with 1 hour retry interval. */ + protected static final int RECONNECT_DELAY_MAX_MILLIS = 60 * 60 * 1000; + + /** Slow poll when attempting connection recovery. */ + protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; + /** Default ping deadline, in seconds. */ + protected final int DEFAULT_PING_DEADLINE = 5; + /** Default max failure count before attempting to network re-registration. */ + protected final int DEFAULT_MAX_PDP_RESET_FAIL = 3; + + /** + * After detecting a potential connection problem, this is the max number + * of subsequent polls before attempting a radio reset. At this point, + * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to + * poll for about 2 more minutes. + */ + protected static final int NO_RECV_POLL_LIMIT = 24; + + // 1 sec. default polling interval when screen is on. + protected static final int POLL_NETSTAT_MILLIS = 1000; + // 10 min. default polling interval when screen is off. + protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; + // 2 min for round trip time + protected static final int POLL_LONGEST_RTT = 120 * 1000; + // 10 for packets without ack + protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10; + // how long to wait before switching back to default APN + protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; + // system property that can override the above value + protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; + // represents an invalid IP address + protected static final String NULL_IP = "0.0.0.0"; + + + // member variables + protected PhoneBase phone; + protected Activity activity = Activity.NONE; + protected State state = State.IDLE; + protected Handler mDataConnectionTracker = null; + + + protected INetStatService netstat; + protected long txPkts, rxPkts, sentSinceLastRecv; + protected int netStatPollPeriod; + protected int mNoRecvPollCount = 0; + protected boolean netStatPollEnabled = false; + + // wifi connection status will be updated by sticky intent + protected boolean mIsWifiConnected = false; + + /** Intent sent when the reconnect alarm fires. */ + protected PendingIntent mReconnectIntent = null; + + /** CID of active data connection */ + protected int cidActive; + + /** + * Default constructor + */ + protected DataConnectionTracker(PhoneBase phone) { + super(); + this.phone = phone; + } + + public Activity getActivity() { + return activity; + } + + public State getState() { + return state; + } + + public 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"; + } + } + + /** + * The data connection is expected to be setup while device + * 1. has Icc card + * 2. registered for data 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. + */ + public abstract boolean isDataConnectionAsDesired(); + + //The data roaming setting is now located in the shared preferences. + // See if the requested preference value is the same as that stored in + // the shared values. If it is not, then update it. + public void setDataOnRoamingEnabled(boolean enabled) { + if (getDataOnRoamingEnabled() != enabled) { + 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); + sendMessage(roamingMsg); + } + + //Retrieve the data roaming setting from the shared preferences. + public boolean getDataOnRoamingEnabled() { + try { + return Settings.Secure.getInt(phone.getContext().getContentResolver(), + Settings.Secure.DATA_ROAMING) > 0; + } catch (SettingNotFoundException snfe) { + return false; + } + } + + // abstract handler methods + protected abstract void onTrySetupData(); + protected abstract void onRoamingOff(); + protected abstract void onRoamingOn(); + protected abstract void onRadioAvailable(); + protected abstract void onRadioOffOrNotAvailable(); + protected abstract void onDataSetupComplete(AsyncResult ar); + protected abstract void onDisconnectDone(AsyncResult ar); + protected abstract void onVoiceCallStarted(); + protected abstract void onVoiceCallEnded(); + + //***** Overridden from Handler + public void handleMessage (Message msg) { + switch (msg.what) { + + case EVENT_TRY_SETUP_DATA: + onTrySetupData(); + break; + + case EVENT_ROAMING_OFF: + onRoamingOff(); + break; + + case EVENT_ROAMING_ON: + onRoamingOn(); + break; + + case EVENT_RADIO_AVAILABLE: + onRadioAvailable(); + break; + + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + onRadioOffOrNotAvailable(); + break; + + case EVENT_DATA_SETUP_COMPLETE: + cidActive = msg.arg1; + onDataSetupComplete((AsyncResult) msg.obj); + break; + + case EVENT_DISCONNECT_DONE: + onDisconnectDone((AsyncResult) msg.obj); + break; + + case EVENT_VOICE_CALL_STARTED: + onVoiceCallStarted(); + break; + + case EVENT_VOICE_CALL_ENDED: + onVoiceCallEnded(); + break; + + default: + Log.e("DATA", "Unidentified event = " + msg.what); + break; + } + } + + /** + * Simply tear down data connections due to radio off + * and don't setup again. + */ + public abstract void cleanConnectionBeforeRadioOff(); + + /** + * Report the current state of data connectivity (enabled or disabled) + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public abstract boolean getDataEnabled(); + + /** + * Report on whether data connectivity is enabled + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public abstract boolean getAnyDataEnabled(); + + /** + * Prevent mobile data connections from being established, + * or once again allow mobile data connections. If the state + * toggles, then either tear down or set up data, as + * appropriate to match the new state. + * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data + * @return {@code true} if the operation succeeded + */ + public abstract boolean setDataEnabled(boolean enable); + + protected abstract void startNetStatPoll(); + + protected abstract void stopNetStatPoll(); + + protected abstract void restartRadio(); + + protected abstract void log(String s); +} diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLink.java b/telephony/java/com/android/internal/telephony/DataLink.java similarity index 82% rename from telephony/java/com/android/internal/telephony/gsm/DataLink.java rename to telephony/java/com/android/internal/telephony/DataLink.java index b822ab45a5e457061a3a777d110cdfc287f0f1bb..8132d9170d067b60c9002e576ddc68709a9678af 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataLink.java +++ b/telephony/java/com/android/internal/telephony/DataLink.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.os.Handler; import android.os.Registrant; @@ -24,14 +24,13 @@ import android.os.Registrant; * * {@hide} */ -abstract class DataLink extends Handler implements DataLinkInterface { +public abstract class DataLink extends Handler implements DataLinkInterface { /** Registrant for link status change notifications. */ - Registrant mLinkChangeRegistrant; - + protected Registrant mLinkChangeRegistrant; protected DataConnectionTracker dataConnection; - DataLink(DataConnectionTracker dc) { + protected DataLink(DataConnectionTracker dc) { dataConnection = dc; } diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java b/telephony/java/com/android/internal/telephony/DataLinkInterface.java similarity index 91% rename from telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java rename to telephony/java/com/android/internal/telephony/DataLinkInterface.java index bca63f2c7f2018ae164d5f8778295bee7e5c07be..e8148a8945a8379a089fcf753dde45bce1405dcd 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java +++ b/telephony/java/com/android/internal/telephony/DataLinkInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.database.Cursor; import android.os.Handler; @@ -24,7 +24,7 @@ import android.os.Handler; * * {@hide} */ -interface DataLinkInterface { +public interface DataLinkInterface { /** * Link state enumeration. * @@ -35,21 +35,21 @@ interface DataLinkInterface { LINK_DOWN, LINK_EXITED } - + /** Normal exit */ final static int EXIT_OK = 0; /** Open failed */ final static int EXIT_OPEN_FAILED = 7; - + /** * Sets the handler for link state change events. - * + * * @param h Handler * @param what User-defined message code * @param obj User object */ void setOnLinkChange(Handler h, int what, Object obj); - + /** * Sets up the data link. */ @@ -59,14 +59,14 @@ interface DataLinkInterface { * Tears down the data link. */ void disconnect(); - + /** - * Returns the exit code for a data link failure. + * Returns the exit code for a data link failure. * * @return exit code */ int getLastLinkExitCode(); - + /** * Sets password information that may be required by the data link * (eg, PAP secrets). diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 81ef623d8f7d1bb924c5803a77286800e7852f3c..79b4afe8698426b72e11cbbc3d975192701d791d 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -33,7 +33,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { private static final boolean DBG = true; private ITelephonyRegistry mRegistry; - /*package*/ + /*package*/ DefaultPhoneNotifier() { mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry")); @@ -94,7 +94,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { public void notifyDataConnection(Phone sender, String reason) { try { - mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), + mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), sender.getInterfaceName(null)); } catch (RemoteException ex) { @@ -119,7 +119,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { // system process is dead } } - + private void log(String s) { Log.d(LOG_TAG, "[PhoneNotifier] " + s); } diff --git a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java b/telephony/java/com/android/internal/telephony/DriverCall.java similarity index 84% rename from telephony/java/com/android/internal/telephony/gsm/DriverCall.java rename to telephony/java/com/android/internal/telephony/DriverCall.java index aab885a0533c32de200efc211de1a21ccab38dd7..0d9a60f2591fd272e58f56ba46fdc868f79441c6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java +++ b/telephony/java/com/android/internal/telephony/DriverCall.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; - +package com.android.internal.telephony; +//import com.android.internal.telephony.*; import android.util.Log; import java.lang.Comparable; import android.telephony.PhoneNumberUtils; @@ -24,10 +23,9 @@ import android.telephony.PhoneNumberUtils; /** * {@hide} */ -public class DriverCall implements Comparable -{ - static final String LOG_TAG = "GSM"; - +public class DriverCall implements Comparable { + static final String LOG_TAG = "RILB"; + public enum State { ACTIVE, HOLDING, @@ -46,13 +44,15 @@ public class DriverCall implements Comparable public String number; public int TOA; public boolean isVoice; + public boolean isVoicePrivacy; public int als; public int numberPresentation; - + public String name; + public int namePresentation; + /** returns null on error */ static DriverCall - fromCLCCLine(String line) - { + fromCLCCLine(String line) { DriverCall ret = new DriverCall(); //+CLCC: 1,0,2,0,0,\"+18005551212\",145 @@ -66,10 +66,10 @@ public class DriverCall implements Comparable ret.isVoice = (0 == p.nextInt()); ret.isMpty = p.nextBoolean(); - + // use ALLOWED as default presentation while parsing CLCC ret.numberPresentation = Connection.PRESENTATION_ALLOWED; - + if (p.hasMore()) { // Some lame implementations return strings // like "NOT AVAILABLE" in the CLCC line @@ -98,24 +98,25 @@ public class DriverCall implements Comparable } public - DriverCall() - { + DriverCall() { } public String - toString() - { + toString() { return "id=" + index + "," - + (isMT ? "mt" : "mo") + "," + state + "," - + (isVoice ? "voice" : "no_voc") + "," + + "toa=" + TOA + "," + (isMpty ? "conf" : "norm") + "," - + TOA + "," + als + ",cli " + numberPresentation; + + (isMT ? "mt" : "mo") + "," + + als + "," + + (isVoice ? "voc" : "nonvoc") + "," + + (isVoicePrivacy ? "evp" : "noevp") + "," + /*+ "number=" + number */ + ",cli=" + numberPresentation + "," + /*+ "name="+ name */ + "," + namePresentation; } public static State - stateFromCLCC(int state) throws ATParseEx - { + stateFromCLCC(int state) throws ATParseEx { switch(state) { case 0: return State.ACTIVE; case 1: return State.HOLDING; @@ -127,7 +128,7 @@ public class DriverCall implements Comparable throw new ATParseEx("illegal call state " + state); } } - + public static int presentationFromCLIP(int cli) throws ATParseEx { @@ -141,12 +142,11 @@ public class DriverCall implements Comparable } } - //***** Comparable Implementation + //***** Comparable Implementation /** For sorting by index */ public int - compareTo (Object o) - { + compareTo (Object o) { DriverCall dc; dc = (DriverCall)o; diff --git a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java b/telephony/java/com/android/internal/telephony/EncodeException.java similarity index 77% rename from telephony/java/com/android/internal/telephony/gsm/EncodeException.java rename to telephony/java/com/android/internal/telephony/EncodeException.java index d546cefd9491b11f69bc7ae3901ce360eb376de6..0436ba0a070b6c281ef7bb10558803c90b3b333e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java +++ b/telephony/java/com/android/internal/telephony/EncodeException.java @@ -14,25 +14,21 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class EncodeException extends Exception -{ - public EncodeException() - { +public class EncodeException extends Exception { + public EncodeException() { super(); } - - public EncodeException(String s) - { + + public EncodeException(String s) { super(s); } - public EncodeException(char c) - { + public EncodeException(char c) { super("Unencodable char: '" + c + "'"); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java similarity index 93% rename from telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java rename to telephony/java/com/android/internal/telephony/GsmAlphabet.java index df34897a5400937c86e0dd3e6dc822f08962ae13..8f4c69caf86d85cf8a8604d3d19a0492e6276c13 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import android.telephony.gsm.SmsMessage; +import android.telephony.SmsMessage; import android.util.SparseIntArray; import android.util.Log; @@ -28,16 +28,15 @@ import android.util.Log; * * {@hide} */ -public class GsmAlphabet -{ +public class GsmAlphabet { static final String LOG_TAG = "GSM"; - + //***** Constants /** - * This escapes extended characters, and when present indicates that the + * This escapes extended characters, and when present indicates that the * following character should * be looked up in the "extended" table * @@ -55,8 +54,7 @@ public class GsmAlphabet * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string */ public static int - charToGsm(char c) - { + charToGsm(char c) { try { return charToGsm(c, false); } catch (EncodeException ex) { @@ -67,7 +65,7 @@ public class GsmAlphabet /** * char to GSM alphabet char - * @param throwException If true, throws EncodeException on invalid char. + * @param throwException If true, throws EncodeException on invalid char. * If false, returns GSM alphabet ' ' char. * * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table @@ -76,10 +74,9 @@ public class GsmAlphabet */ public static int - charToGsm(char c, boolean throwException) throws EncodeException - { + charToGsm(char c, boolean throwException) throws EncodeException { int ret; - + ret = charToGsm.get(c, -1); if (ret == -1) { @@ -99,7 +96,7 @@ public class GsmAlphabet return ret; } - + /** * char to extended GSM alphabet char @@ -110,10 +107,9 @@ public class GsmAlphabet * */ public static int - charToGsmExtended(char c) - { + charToGsmExtended(char c) { int ret; - + ret = charToGsmExtended.get(c, -1); if (ret == -1) { @@ -124,34 +120,32 @@ public class GsmAlphabet } /** - * Converts a character in the GSM alphabet into a char + * Converts a character in the GSM alphabet into a char * * if GSM_EXTENDED_ESCAPE is passed, 0xffff is returned. In this case, - * the following character in the stream should be decoded with + * the following character in the stream should be decoded with * gsmExtendedToChar() * * If an unmappable value is passed (one greater than 127), ' ' is returned */ public static char - gsmToChar(int gsmChar) - { + gsmToChar(int gsmChar) { return (char)gsmToChar.get(gsmChar, ' '); } - + /** - * Converts a character in the extended GSM alphabet into a char + * Converts a character in the extended GSM alphabet into a char * * if GSM_EXTENDED_ESCAPE is passed, ' ' is returned since no second * extension page has yet been defined (see Note 1 in table 6.2.1.1 of * TS 23.038 v7.00) - * + * * If an unmappable value is passed , ' ' is returned */ public static char - gsmExtendedToChar(int gsmChar) - { + gsmExtendedToChar(int gsmChar) { int ret; ret = gsmExtendedToChar.get(gsmChar, -1); @@ -205,7 +199,7 @@ public class GsmAlphabet } /** - * Converts a String into a byte array containing + * Converts a String into a byte array containing * the 7-bit packed GSM Alphabet representation of the string. * * Unencodable chars are encoded as spaces @@ -224,7 +218,7 @@ public class GsmAlphabet } /** - * Converts a String into a byte array containing + * Converts a String into a byte array containing * the 7-bit packed GSM Alphabet representation of the string. * * Byte 0 in the returned byte array is the count of septets used @@ -238,7 +232,7 @@ public class GsmAlphabet * enforced maximum. * @param startingBitOffset the number of padding bits to put before * the start of the first septet at the begining of the array - * @param throwException If true, throws EncodeException on invalid char. + * @param throwException If true, throws EncodeException on invalid char. * If false, replaces unencodable char with GSM alphabet space char. * * @throws EncodeException if String is too large to encode @@ -294,27 +288,26 @@ public class GsmAlphabet * @param bitOffset the bit offset that the septet should be packed at * (septet index * 7) */ - private static void - packSmsChar(byte[] packedChars, int bitOffset, int value) - { + private static void + packSmsChar(byte[] packedChars, int bitOffset, int value) { int byteOffset = bitOffset / 8; int shift = bitOffset % 8; packedChars[++byteOffset] |= value << shift; if (shift > 1) { - packedChars[++byteOffset] = (byte)(value >> (8 - shift)); - } + packedChars[++byteOffset] = (byte)(value >> (8 - shift)); + } } /** - * Convert a GSM alphabet 7 bit packed string (SMS string) into a + * Convert a GSM alphabet 7 bit packed string (SMS string) into a * {@link java.lang.String}. * * See TS 23.038 6.1.2.1 for SMS Character Packing * * @param pdu the raw data from the pdu - * @param offset the byte offset of + * @param offset the byte offset of * @param lengthSeptets string length in septets, not bytes * @return String representation or null on decoding exception */ @@ -324,27 +317,26 @@ public class GsmAlphabet } /** - * Convert a GSM alphabet 7 bit packed string (SMS string) into a + * Convert a GSM alphabet 7 bit packed string (SMS string) into a * {@link java.lang.String}. * * See TS 23.038 6.1.2.1 for SMS Character Packing * * @param pdu the raw data from the pdu - * @param offset the byte offset of + * @param offset the byte offset of * @param lengthSeptets string length in septets, not bytes * @param numPaddingBits the number of padding bits before the start of the * string in the first byte * @return String representation or null on decoding exception */ public static String gsm7BitPackedToString(byte[] pdu, int offset, - int lengthSeptets, int numPaddingBits) - { + int lengthSeptets, int numPaddingBits) { StringBuilder ret = new StringBuilder(lengthSeptets); boolean prevCharWasEscape; - + try { prevCharWasEscape = false; - + for (int i = 0 ; i < lengthSeptets ; i++) { int bitOffset = (7 * i) + numPaddingBits; @@ -381,15 +373,14 @@ public class GsmAlphabet /** - * Convert a GSM alphabet string that's stored in 8-bit unpacked + * Convert a GSM alphabet string that's stored in 8-bit unpacked * format (as it often appears in SIM records) into a String * * Field may be padded with trailing 0xff's. The decode stops * at the first 0xff encountered. */ public static String - gsm8BitUnpackedToString(byte[] data, int offset, int length) - { + gsm8BitUnpackedToString(byte[] data, int offset, int length) { boolean prevWasEscape; StringBuilder ret = new StringBuilder(length); @@ -420,8 +411,8 @@ public class GsmAlphabet prevWasEscape = false; } } - - return ret.toString(); + + return ret.toString(); } /** @@ -429,8 +420,7 @@ public class GsmAlphabet * array */ public static byte[] - stringToGsm8BitPacked(String s) - { + stringToGsm8BitPacked(String s) { byte[] ret; int septets = 0; @@ -452,15 +442,14 @@ public class GsmAlphabet * * Field is padded with 0xff's, string is truncated if necessary */ - + public static void - stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) - { + stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) { int outByteIndex = offset; // Septets are stored in byte-aligned octets for (int i = 0, sz = s.length() - ; i < sz && (outByteIndex - offset) < length + ; i < sz && (outByteIndex - offset) < length ; i++ ) { char c = s.charAt(i); @@ -475,7 +464,7 @@ public class GsmAlphabet dest[outByteIndex++] = GSM_EXTENDED_ESCAPE; - v = GsmAlphabet.charToGsmExtended(c); + v = GsmAlphabet.charToGsmExtended(c); } dest[outByteIndex++] = (byte)v; @@ -492,8 +481,7 @@ public class GsmAlphabet * needed to represent this character. Counts unencodable char as 1 septet. */ public static int - countGsmSeptets(char c) - { + countGsmSeptets(char c) { try { return countGsmSeptets(c, false); } catch (EncodeException ex) { @@ -509,21 +497,20 @@ public class GsmAlphabet * char. Otherwise, counts invalid char as 1 septet */ public static int - countGsmSeptets(char c, boolean throwsException) throws EncodeException - { - if (charToGsm.get(c, -1) != -1) { - return 1; - } - - if (charToGsmExtended.get(c, -1) != -1) { - return 2; - } + countGsmSeptets(char c, boolean throwsException) throws EncodeException { + if (charToGsm.get(c, -1) != -1) { + return 1; + } + + if (charToGsmExtended.get(c, -1) != -1) { + return 2; + } if (throwsException) { throw new EncodeException(c); - } else { - // count as a space char - return 1; + } else { + // count as a space char + return 1; } } @@ -532,8 +519,7 @@ public class GsmAlphabet * needed to represent this string. Counts unencodable char as 1 septet. */ public static int - countGsmSeptets(CharSequence s) - { + countGsmSeptets(CharSequence s) { try { return countGsmSeptets(s, false); } catch (EncodeException ex) { @@ -549,8 +535,7 @@ public class GsmAlphabet * char. Otherwise, counts invalid char as 1 septet */ public static int - countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException - { + countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException { int charIndex = 0; int sz = s.length(); int count = 0; @@ -559,9 +544,9 @@ public class GsmAlphabet count += countGsmSeptets(s.charAt(charIndex), throwsException); charIndex++; } - + return count; - } + } /** * Returns the index into s of the first character @@ -623,7 +608,7 @@ public class GsmAlphabet * @return index of first character that won't fit, or the length * of the entire string if everything fits */ - public static int + public static int findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException { if (encodingType == SmsMessage.ENCODING_7BIT) { return findGsmSeptetLimitIndex(s, start, limit); @@ -643,10 +628,10 @@ public class GsmAlphabet private static final SparseIntArray gsmToChar = new SparseIntArray(); private static final SparseIntArray charToGsmExtended = new SparseIntArray(); private static final SparseIntArray gsmExtendedToChar = new SparseIntArray(); - + static { int i = 0; - + charToGsm.put('@', i++); charToGsm.put('\u00a3', i++); charToGsm.put('$', i++); @@ -663,7 +648,7 @@ public class GsmAlphabet charToGsm.put('\r', i++); charToGsm.put('\u00c5', i++); charToGsm.put('\u00e5', i++); - + charToGsm.put('\u0394', i++); charToGsm.put('_', i++); charToGsm.put('\u03a6', i++); @@ -680,7 +665,7 @@ public class GsmAlphabet charToGsm.put('\u00e6', i++); charToGsm.put('\u00df', i++); charToGsm.put('\u00c9', i++); - + charToGsm.put(' ', i++); charToGsm.put('!', i++); charToGsm.put('"', i++); @@ -697,7 +682,7 @@ public class GsmAlphabet charToGsm.put('-', i++); charToGsm.put('.', i++); charToGsm.put('/', i++); - + charToGsm.put('0', i++); charToGsm.put('1', i++); charToGsm.put('2', i++); @@ -714,7 +699,7 @@ public class GsmAlphabet charToGsm.put('=', i++); charToGsm.put('>', i++); charToGsm.put('?', i++); - + charToGsm.put('\u00a1', i++); charToGsm.put('A', i++); charToGsm.put('B', i++); @@ -731,7 +716,7 @@ public class GsmAlphabet charToGsm.put('M', i++); charToGsm.put('N', i++); charToGsm.put('O', i++); - + charToGsm.put('P', i++); charToGsm.put('Q', i++); charToGsm.put('R', i++); @@ -748,7 +733,7 @@ public class GsmAlphabet charToGsm.put('\u0147', i++); charToGsm.put('\u00dc', i++); charToGsm.put('\u00a7', i++); - + charToGsm.put('\u00bf', i++); charToGsm.put('a', i++); charToGsm.put('b', i++); @@ -765,7 +750,7 @@ public class GsmAlphabet charToGsm.put('m', i++); charToGsm.put('n', i++); charToGsm.put('o', i++); - + charToGsm.put('p', i++); charToGsm.put('q', i++); charToGsm.put('r', i++); @@ -782,8 +767,8 @@ public class GsmAlphabet charToGsm.put('\u00f1', i++); charToGsm.put('\u00fc', i++); charToGsm.put('\u00e0', i++); - - + + charToGsmExtended.put('\f', 10); charToGsmExtended.put('^', 20); charToGsmExtended.put('{', 40); @@ -794,12 +779,12 @@ public class GsmAlphabet charToGsmExtended.put(']', 62); charToGsmExtended.put('|', 64); charToGsmExtended.put('\u20ac', 101); - + int size = charToGsm.size(); for (int j=0; jThe following code snippet demonstrates a static method to - * retrieve the ISimPhoneBook interface from Android:

        - *
        private static ISimPhoneBook getSimPhoneBookInterface()
        + * retrieve the IIccPhoneBook interface from Android:

        + *
        private static IIccPhoneBook getSimPhoneBookInterface()
                     throws DeadObjectException {
             IServiceManager sm = ServiceManagerNative.getDefault();
        -    ISimPhoneBook spb;
        -    spb = ISimPhoneBook.Stub.asInterface(sm.getService("simphonebook"));
        +    IIccPhoneBook spb;
        +    spb = IIccPhoneBook.Stub.asInterface(sm.getService("iccphonebook"));
             return spb;
         }
          * 
        */ -interface ISimPhoneBook { +interface IIccPhoneBook { /** * Loads the AdnRecords in efid and returns them as a diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index 00cbaf98bf14e48d28a165c17476d870db27bfbe..e74b9e4a10999a4777e4eecdc375935d347ce484 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -39,9 +39,9 @@ interface IPhoneSubInfo { String getSubscriberId(); /** - * Retrieves the serial number of the SIM, if applicable. + * Retrieves the serial number of the ICC, if applicable. */ - String getSimSerialNumber(); + String getIccSerialNumber(); /** * Retrieves the phone number string for line 1. @@ -53,13 +53,13 @@ interface IPhoneSubInfo { */ String getLine1AlphaTag(); - /** - * Retrieves the voice mail number. - */ + /** + * Retrieves the voice mail number. + */ String getVoiceMailNumber(); - /** - * Retrieves the alpha identifier associated with the voice mail number. - */ + /** + * Retrieves the alpha identifier associated with the voice mail number. + */ String getVoiceMailAlphaTag(); } diff --git a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl similarity index 74% rename from telephony/java/com/android/internal/telephony/gsm/ISms.aidl rename to telephony/java/com/android/internal/telephony/ISms.aidl index 904a54e2f03e1057ad4e06f4d5a40bc0bbb72c3a..257f1e62b9a7dd2b6c13c23edfda2f62abc3cbe8 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -14,20 +14,20 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.app.PendingIntent; -import com.android.internal.telephony.gsm.SmsRawData; +import com.android.internal.telephony.SmsRawData; -/** Interface for applications to access the SIM phone book. +/** Interface for applications to access the ICC phone book. * *

        The following code snippet demonstrates a static method to - * retrieve the ISimSms interface from Android:

        - *
        private static ISimSms getSimSmsInterface()
        + * retrieve the ISms interface from Android:

        + *
        private static ISms getSmsInterface()
                     throws DeadObjectException {
             IServiceManager sm = ServiceManagerNative.getDefault();
        -    ISimSms ss;
        -    ss = ISimSms.Stub.asInterface(sm.getService("isms"));
        +    ISms ss;
        +    ss = ISms.Stub.asInterface(sm.getService("isms"));
             return ss;
         }
          * 
        @@ -35,45 +35,45 @@ import com.android.internal.telephony.gsm.SmsRawData; interface ISms { /** - * Retrieves all messages currently stored on SIM. + * Retrieves all messages currently stored on ICC. * - * @return list of SmsRawData of all sms on SIM + * @return list of SmsRawData of all sms on ICC */ - List getAllMessagesFromSimEf(); + List getAllMessagesFromIccEf(); /** - * Update the specified message on the SIM. + * Update the specified message on the ICC. * * @param messageIndex record index of message to update - * @param newStatus new message status (STATUS_ON_SIM_READ, - * STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT, - * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) + * @param newStatus new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) * @param pdu the raw PDU to store * @return success or not * */ - boolean updateMessageOnSimEf(int messageIndex, int newStatus, + boolean updateMessageOnIccEf(int messageIndex, int newStatus, in byte[] pdu); /** - * Copy a raw SMS PDU to the SIM. + * Copy a raw SMS PDU to the ICC. * * @param pdu the raw PDU to store - * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, - * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) * @return success or not * */ - boolean copyMessageToSimEf(int status, in byte[] pdu, in byte[] smsc); + boolean copyMessageToIccEf(int status, in byte[] pdu, in byte[] smsc); /** * Send a SMS * * @param smsc the SMSC to send the message through, or NULL for the - * defatult SMSC + * default SMSC * @param pdu the raw PDU to send * @param sentIntent if not NULL this Intent is - * broadcast when the message is sucessfully sent, or failed. + * broadcast when the message is successfully sent, or failed. * The result code will be Activity.RESULT_OK for success, * or one of these errors: * RESULT_ERROR_GENERIC_FAILURE @@ -88,13 +88,13 @@ interface ISms { /** * Send a multi-part text based SMS. - * + * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use * the current default SMSC * @param parts an ArrayList of strings that, in order, * comprise the original message - * @param sentIntents if not null, an ArrayList of + * @param sentIntents if not null, an ArrayList of * PendingIntents (one for each message part) that is * broadcast when the corresponding message part has been sent. * The result code will be Activity.RESULT_OK for success, @@ -102,7 +102,7 @@ interface ISms { * RESULT_ERROR_GENERIC_FAILURE * RESULT_ERROR_RADIO_OFF * RESULT_ERROR_NULL_PDU. - * @param deliveryIntents if not null, an ArrayList of + * @param deliveryIntents if not null, an ArrayList of * PendingIntents (one for each message part) that is * broadcast when the corresponding message part has been delivered * to the recipient. The raw pdu of the status report is in the diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 2b4195ba15e19939b67dc4612aef54b7b0b898f4..bab0603230ea7d142216b042ae69fc536f7de37f 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -21,7 +21,7 @@ import java.util.List; import android.telephony.NeighboringCellInfo; /** - * Interface used to interact with the phone. Mostly this is used by the + * Interface used to interact with the phone. Mostly this is used by the * TelephonyManager class. A few places are still using this directly. * Please clean them up if possible and use TelephonyManager insteadl. * @@ -135,7 +135,7 @@ interface ITelephony { /** * Cancels the missed calls notification. */ - void cancelMissedCallsNotification(); + void cancelMissedCallsNotification(); /** * Supply a pin to unlock the SIM. Blocks until a result is determined. @@ -147,7 +147,7 @@ interface ITelephony { /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated * without SEND (so dial is not appropriate). - * + * * @param dialString the MMI command to be executed. * @return true if MMI command is executed. */ @@ -213,4 +213,13 @@ interface ITelephony { int getCallState(); int getDataActivity(); int getDataState(); + + /** + * Returns the current active phone type as integer. + * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE + * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE + */ + int getActivePhoneType(); + } + diff --git a/telephony/java/com/android/internal/telephony/SimCard.java b/telephony/java/com/android/internal/telephony/IccCard.java similarity index 70% rename from telephony/java/com/android/internal/telephony/SimCard.java rename to telephony/java/com/android/internal/telephony/IccCard.java index 03b366f8ba381660ca9418bb1c13c7431308bd64..d7ad492bdd4aa29787d6ead28bcbebb889c87999 100644 --- a/telephony/java/com/android/internal/telephony/SimCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -22,35 +22,34 @@ import android.os.Handler; /** * {@hide} */ -public interface SimCard -{ - /* The extra data for broacasting intent INTENT_SIM_STATE_CHANGE */ - static public final String INTENT_KEY_SIM_STATE = "ss"; - /* NOT_READY means the SIM interface is not ready (eg, radio is off or powering on) */ - static public final String INTENT_VALUE_SIM_NOT_READY = "NOT_READY"; - /* ABSENT means SIM is missing */ - static public final String INTENT_VALUE_SIM_ABSENT = "ABSENT"; - /* LOCKED means SIM is locked by pin or by network */ - static public final String INTENT_VALUE_SIM_LOCKED = "LOCKED"; - /* READY means SIM is ready to access */ - static public final String INTENT_VALUE_SIM_READY = "READY"; - /* IMSI means SIM IMSI is ready in property */ - static public final String INTENT_VALUE_SIM_IMSI = "IMSI"; - /* LOADED means all SIM records, including IMSI, are loaded */ - static public final String INTENT_VALUE_SIM_LOADED = "LOADED"; - /* The extra data for broacasting intent INTENT_SIM_STATE_CHANGE */ +public interface IccCard { + /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ + static public final String INTENT_KEY_ICC_STATE = "ss"; + /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */ + static public final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY"; + /* ABSENT means ICC is missing */ + static public final String INTENT_VALUE_ICC_ABSENT = "ABSENT"; + /* LOCKED means ICC is locked by pin or by network */ + static public final String INTENT_VALUE_ICC_LOCKED = "LOCKED"; + /* READY means ICC is ready to access */ + static public final String INTENT_VALUE_ICC_READY = "READY"; + /* IMSI means ICC IMSI is ready in property */ + static public final String INTENT_VALUE_ICC_IMSI = "IMSI"; + /* LOADED means all ICC records, including IMSI, are loaded */ + static public final String INTENT_VALUE_ICC_LOADED = "LOADED"; + /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ static public final String INTENT_KEY_LOCKED_REASON = "reason"; - /* PIN means SIM is locked on PIN1 */ + /* PIN means ICC is locked on PIN1 */ static public final String INTENT_VALUE_LOCKED_ON_PIN = "PIN"; - /* PUK means SIM is locked on PUK1 */ + /* PUK means ICC is locked on PUK1 */ static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK"; - /* NETWORK means SIM is locked on NETWORK PERSONALIZATION */ + /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */ static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK"; /* - UNKNOWN is a transient state, for example, after uesr inputs sim pin under - PIN_REQUIRED state, the query for sim status returns UNKNOWN before it + UNKNOWN is a transient state, for example, after uesr inputs ICC pin under + PIN_REQUIRED state, the query for ICC status returns UNKNOWN before it turns to READY */ public enum State { @@ -73,7 +72,7 @@ public interface SimCard * Notifies handler of any transition into State.ABSENT */ void registerForAbsent(Handler h, int what, Object obj); - void unregisterForAbsent(Handler h); + void unregisterForAbsent(Handler h); /** * Notifies handler of any transition into State.isPinLocked() @@ -88,7 +87,7 @@ public interface SimCard void unregisterForNetworkLocked(Handler h); /** - * Supply the SIM PIN to the SIM + * Supply the ICC PIN to the ICC * * When the operation is complete, onComplete will be sent to it's * Handler. @@ -100,11 +99,11 @@ public interface SimCard * * If the supplied PIN is incorrect: * ((AsyncResult)onComplete.obj).exception != null - * && ((AsyncResult)onComplete.obj).exception + * && ((AsyncResult)onComplete.obj).exception * instanceof com.android.internal.telephony.gsm.CommandException) * && ((CommandException)(((AsyncResult)onComplete.obj).exception)) * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT - * + * * */ @@ -114,30 +113,30 @@ public interface SimCard void supplyPuk2 (String puk2, String newPin2, Message onComplete); /** - * Check whether sim pin lock is enabled + * Check whether ICC pin lock is enabled * This is a sync call which returns the cached pin enabled state * - * @return true for sim locked enabled - * false for sim locked disabled + * @return true for ICC locked enabled + * false for ICC locked disabled */ - boolean getSimLockEnabled (); + boolean getIccLockEnabled (); /** - * Set the sim pin lock enabled or disabled + * Set the ICC pin lock enabled or disabled * When the operation is complete, onComplete will be sent to its handler * * @param enabled "true" for locked "false" for unlocked. - * @param password needed to change the sim pin state, aka. Pin1 + * @param password needed to change the ICC pin state, aka. Pin1 * @param onComplete * onComplete.obj will be an AsyncResult * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void setSimLockEnabled(boolean enabled, String password, Message onComplete); + void setIccLockEnabled(boolean enabled, String password, Message onComplete); /** - * Change the sim password used in sim pin lock + * Change the ICC password used in ICC pin lock * When the operation is complete, onComplete will be sent to its handler * * @param oldPassword is the old password @@ -147,33 +146,33 @@ public interface SimCard * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void changeSimLockPassword(String oldPassword, String newPassword, + void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete); /** - * Check whether sim fdn (fixed dialing number) is enabled + * Check whether ICC fdn (fixed dialing number) is enabled * This is a sync call which returns the cached pin enabled state * - * @return true for sim fdn enabled - * false for sim fdn disabled + * @return true for ICC fdn enabled + * false for ICC fdn disabled */ - boolean getSimFdnEnabled (); + boolean getIccFdnEnabled (); /** - * Set the sim fdn enabled or disabled + * Set the ICC fdn enabled or disabled * When the operation is complete, onComplete will be sent to its handler * * @param enabled "true" for locked "false" for unlocked. - * @param password needed to change the sim fdn enable, aka Pin2 + * @param password needed to change the ICC fdn enable, aka Pin2 * @param onComplete * onComplete.obj will be an AsyncResult * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void setSimFdnEnabled(boolean enabled, String password, Message onComplete); + void setIccFdnEnabled(boolean enabled, String password, Message onComplete); /** - * Change the sim password used in sim fdn enable + * Change the ICC password used in ICC fdn enable * When the operation is complete, onComplete will be sent to its handler * * @param oldPassword is the old password @@ -183,13 +182,13 @@ public interface SimCard * ((AsyncResult)onComplete.obj).exception == null on success * ((AsyncResult)onComplete.obj).exception != null on fail */ - void changeSimFdnPassword(String oldPassword, String newPassword, + void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete); void supplyNetworkDepersonalization (String pin, Message onComplete); /** - * Returns service provider name stored in SIM card. + * Returns service provider name stored in ICC card. * If there is no service provider name associated or the record is not * yet available, null will be returned

        * @@ -199,7 +198,7 @@ public interface SimCard * * Also available via Android property "gsm.sim.operator.alpha" * - * @return Service Provider Name stored in SIM card + * @return Service Provider Name stored in ICC card * null if no service provider name associated or the record is not * yet available * diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..9f60a6cffec8108b6e6503c8e5bf070b983e8795 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java @@ -0,0 +1,178 @@ +/* + * 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; + + +/** + * See also RIL_AppStatus in include/telephony/ril.h + * + * {@hide} + */ +public class IccCardApplication { + public enum AppType{ + APPTYPE_UNKNOWN, + APPTYPE_SIM, + APPTYPE_USIM, + APPTYPE_RUIM, + APPTYPE_CSIM + }; + + public enum AppState{ + APPSTATE_UNKNOWN, + APPSTATE_DETECTED, + APPSTATE_PIN, + APPSTATE_PUK, + APPSTATE_SUBSCRIPTION_PERSO, + APPSTATE_READY; + + boolean isPinRequired() { + return this == APPSTATE_PIN; + } + + boolean isPukRequired() { + return this == APPSTATE_PUK; + } + + boolean isSubscriptionPersoEnabled() { + return this == APPSTATE_SUBSCRIPTION_PERSO; + } + + boolean isAppReady() { + return this == APPSTATE_READY; + } + + boolean isAppNotReady() { + return this == APPSTATE_UNKNOWN || + this == APPSTATE_DETECTED; + } + }; + + public enum PersoSubState{ + PERSOSUBSTATE_UNKNOWN, + PERSOSUBSTATE_IN_PROGRESS, + PERSOSUBSTATE_READY, + PERSOSUBSTATE_SIM_NETWORK, + PERSOSUBSTATE_SIM_NETWORK_SUBSET, + PERSOSUBSTATE_SIM_CORPORATE, + PERSOSUBSTATE_SIM_SERVICE_PROVIDER, + PERSOSUBSTATE_SIM_SIM, + PERSOSUBSTATE_SIM_NETWORK_PUK, + PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK, + PERSOSUBSTATE_SIM_CORPORATE_PUK, + PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK, + PERSOSUBSTATE_SIM_SIM_PUK, + PERSOSUBSTATE_RUIM_NETWORK1, + PERSOSUBSTATE_RUIM_NETWORK2, + PERSOSUBSTATE_RUIM_HRPD, + PERSOSUBSTATE_RUIM_CORPORATE, + PERSOSUBSTATE_RUIM_SERVICE_PROVIDER, + PERSOSUBSTATE_RUIM_RUIM, + PERSOSUBSTATE_RUIM_NETWORK1_PUK, + PERSOSUBSTATE_RUIM_NETWORK2_PUK, + PERSOSUBSTATE_RUIM_HRPD_PUK, + PERSOSUBSTATE_RUIM_CORPORATE_PUK, + PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK, + PERSOSUBSTATE_RUIM_RUIM_PUK; + + boolean isPersoSubStateUnknown() { + return this == PERSOSUBSTATE_UNKNOWN; + } + }; + + public AppType app_type; + public AppState app_state; + // applicable only if app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO + public PersoSubState perso_substate; + // null terminated string, e.g., from 0xA0, 0x00 -> 0x41, 0x30, 0x30, 0x30 */ + public String aid; + // null terminated string + public String app_label; + // applicable to USIM and CSIM + public int pin1_replaced; + public int pin1; + public int pin2; + + AppType AppTypeFromRILInt(int type) { + AppType newType; + /* RIL_AppType ril.h */ + switch(type) { + case 0: newType = AppType.APPTYPE_UNKNOWN; break; + case 1: newType = AppType.APPTYPE_SIM; break; + case 2: newType = AppType.APPTYPE_USIM; break; + case 3: newType = AppType.APPTYPE_RUIM; break; + case 4: newType = AppType.APPTYPE_CSIM; break; + default: + throw new RuntimeException( + "Unrecognized RIL_AppType: " +type); + } + return newType; + } + + AppState AppStateFromRILInt(int state) { + AppState newState; + /* RIL_AppState ril.h */ + switch(state) { + case 0: newState = AppState.APPSTATE_UNKNOWN; break; + case 1: newState = AppState.APPSTATE_DETECTED; break; + case 2: newState = AppState.APPSTATE_PIN; break; + case 3: newState = AppState.APPSTATE_PUK; break; + case 4: newState = AppState.APPSTATE_SUBSCRIPTION_PERSO; break; + case 5: newState = AppState.APPSTATE_READY; break; + default: + throw new RuntimeException( + "Unrecognized RIL_AppState: " +state); + } + return newState; + } + + PersoSubState PersoSubstateFromRILInt(int substate) { + PersoSubState newSubState; + /* RIL_PeroSubstate ril.h */ + switch(substate) { + case 0: newSubState = PersoSubState.PERSOSUBSTATE_UNKNOWN; break; + case 1: newSubState = PersoSubState.PERSOSUBSTATE_IN_PROGRESS; break; + case 2: newSubState = PersoSubState.PERSOSUBSTATE_READY; break; + case 3: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK; break; + case 4: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET; break; + case 5: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE; break; + case 6: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER; break; + case 7: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM; break; + case 8: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_PUK; break; + case 9: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK; break; + case 10: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE_PUK; break; + case 11: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK; break; + case 12: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM_PUK; break; + case 13: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1; break; + case 14: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2; break; + case 15: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD; break; + case 16: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE; break; + case 17: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER; break; + case 18: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM; break; + case 19: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1_PUK; break; + case 20: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2_PUK; break; + case 21: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD_PUK ; break; + case 22: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE_PUK; break; + case 23: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK; break; + case 24: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM_PUK; break; + default: + throw new RuntimeException( + "Unrecognized RIL_PersoSubstate: " +substate); + } + return newSubState; + } + +} diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..b602b1c68cc2e4128ae06d9f88f75651d9d588ca --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccCardStatus.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.internal.telephony; + +import java.util.ArrayList; + +/** + * See also RIL_CardStatus in include/telephony/ril.h + * + * {@hide} + */ +public class IccCardStatus { + static final int CARD_MAX_APPS = 8; + + public enum CardState { + CARDSTATE_ABSENT, + CARDSTATE_PRESENT, + CARDSTATE_ERROR; + + boolean isCardPresent() { + return this == CARDSTATE_PRESENT; + } + }; + + public enum PinState { + PINSTATE_UNKNOWN, + PINSTATE_ENABLED_NOT_VERIFIED, + PINSTATE_ENABLED_VERIFIED, + PINSTATE_DISABLED, + PINSTATE_ENABLED_BLOCKED, + PINSTATE_ENABLED_PERM_BLOCKED + }; + + public CardState card_state; + public PinState universal_pin_state; + public int gsm_umts_subscription_app_index; + public int cdma_subscription_app_index; + public int num_applications; + + ArrayList application = new ArrayList(CARD_MAX_APPS); + + CardState CardStateFromRILInt(int state) { + CardState newState; + /* RIL_CardState ril.h */ + switch(state) { + case 0: newState = CardState.CARDSTATE_ABSENT; break; + case 1: newState = CardState.CARDSTATE_PRESENT; break; + case 2: newState = CardState.CARDSTATE_ERROR; break; + default: + throw new RuntimeException( + "Unrecognized RIL_CardState: " +state); + } + return newState; + } + + PinState PinStateFromRILInt(int state) { + PinState newState; + /* RIL_PinState ril.h */ + switch(state) { + case 0: newState = PinState.PINSTATE_UNKNOWN; break; + case 1: newState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; break; + case 2: newState = PinState.PINSTATE_ENABLED_VERIFIED; break; + case 3: newState = PinState.PINSTATE_DISABLED; break; + case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break; + case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break; + default: + throw new RuntimeException( + "Unrecognized RIL_PinState: " +state); + } + return newState; + } +} diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..014fbb6f6973250d6b35a4ed5277d4a3d842a4a8 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccConstants.java @@ -0,0 +1,64 @@ +/* + * 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; + +/** + * {@hide} + */ +public interface IccConstants { + // GSM SIM file ids from TS 51.011 + static final int EF_ADN = 0x6F3A; + static final int EF_FDN = 0x6F3B; + static final int EF_SDN = 0x6F49; + static final int EF_EXT1 = 0x6F4A; + static final int EF_EXT2 = 0x6F4B; + static final int EF_EXT3 = 0x6F4C; + static final int EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN] + static final int EF_MWIS = 0x6FCA; + static final int EF_MBDN = 0x6fc7; + static final int EF_PNN = 0x6fc5; + static final int EF_SPN = 0x6F46; + static final int EF_SMS = 0x6F3C; + static final int EF_ICCID = 0x2fe2; + static final int EF_AD = 0x6FAD; + static final int EF_MBI = 0x6fc9; + static final int EF_MSISDN = 0x6f40; + static final int EF_SPDI = 0x6fcd; + static final int EF_SST = 0x6f38; + static final int EF_CFIS = 0x6FCB; + static final int EF_IMG = 0x4f20; + + // GSM SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6 + static final int EF_MAILBOX_CPHS = 0x6F17; + static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11; + static final int EF_CFF_CPHS = 0x6F13; + static final int EF_SPN_CPHS = 0x6f14; + static final int EF_SPN_SHORT_CPHS = 0x6f18; + static final int EF_INFO_CPHS = 0x6f16; + + // CDMA RUIM file ids from 3GPP2 C.S0023-0 + static final int EF_CST = 0x6f32; + static final int EF_RUIM_SPN =0x6F41; + + // SMS record length from TS 51.011 10.5.3 + static public final int SMS_RECORD_LENGTH = 176; + + static final String MF_SIM = "3F00"; + static final String DF_TELECOM = "7F10"; + static final String DF_GRAPHICS = "5F50"; + static final String DF_GSM = "7F20"; +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java b/telephony/java/com/android/internal/telephony/IccException.java similarity index 79% rename from telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java rename to telephony/java/com/android/internal/telephony/IccException.java index 72790d0da5ce4164cab343bf421542e77bc2ee28..1659a4e117c7cc6fa5d689996ffbec73a740734c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java +++ b/telephony/java/com/android/internal/telephony/IccException.java @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class SimFileTypeMismatch extends SimException -{ - SimFileTypeMismatch() - { +public class IccException extends Exception { + public IccException() { } - SimFileTypeMismatch(String s) - { + public IccException(String s) { super(s); } } diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..92ddd2c2cb45b82ded3fa2c1da6884ac33d2d00d --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java @@ -0,0 +1,544 @@ +/* + * 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.os.*; +import android.util.Log; +import java.util.ArrayList; + +/** + * {@hide} + */ +public abstract class IccFileHandler extends Handler implements IccConstants { + + //from TS 11.11 9.1 or elsewhere + static protected final int COMMAND_READ_BINARY = 0xb0; + static protected final int COMMAND_UPDATE_BINARY = 0xd6; + static protected final int COMMAND_READ_RECORD = 0xb2; + static protected final int COMMAND_UPDATE_RECORD = 0xdc; + static protected final int COMMAND_SEEK = 0xa2; + static protected final int COMMAND_GET_RESPONSE = 0xc0; + + // from TS 11.11 9.2.5 + static protected final int READ_RECORD_MODE_ABSOLUTE = 4; + + //***** types of files TS 11.11 9.3 + static protected final int EF_TYPE_TRANSPARENT = 0; + static protected final int EF_TYPE_LINEAR_FIXED = 1; + static protected final int EF_TYPE_CYCLIC = 3; + + //***** types of files TS 11.11 9.3 + static protected final int TYPE_RFU = 0; + static protected final int TYPE_MF = 1; + static protected final int TYPE_DF = 2; + static protected final int TYPE_EF = 4; + + // size of GET_RESPONSE for EF's + static protected final int GET_RESPONSE_EF_SIZE_BYTES = 15; + static protected final int GET_RESPONSE_EF_IMG_SIZE_BYTES = 10; + + // Byte order received in response to COMMAND_GET_RESPONSE + // Refer TS 51.011 Section 9.2.1 + static protected final int RESPONSE_DATA_RFU_1 = 0; + static protected final int RESPONSE_DATA_RFU_2 = 1; + + static protected final int RESPONSE_DATA_FILE_SIZE_1 = 2; + static protected final int RESPONSE_DATA_FILE_SIZE_2 = 3; + + static protected final int RESPONSE_DATA_FILE_ID_1 = 4; + static protected final int RESPONSE_DATA_FILE_ID_2 = 5; + static protected final int RESPONSE_DATA_FILE_TYPE = 6; + static protected final int RESPONSE_DATA_RFU_3 = 7; + static protected final int RESPONSE_DATA_ACCESS_CONDITION_1 = 8; + static protected final int RESPONSE_DATA_ACCESS_CONDITION_2 = 9; + static protected final int RESPONSE_DATA_ACCESS_CONDITION_3 = 10; + static protected final int RESPONSE_DATA_FILE_STATUS = 11; + static protected final int RESPONSE_DATA_LENGTH = 12; + static protected final int RESPONSE_DATA_STRUCTURE = 13; + static protected final int RESPONSE_DATA_RECORD_LENGTH = 14; + + + //***** Events + + /** Finished retrieving size of transparent EF; start loading. */ + static protected final int EVENT_GET_BINARY_SIZE_DONE = 4; + /** Finished loading contents of transparent EF; post result. */ + static protected final int EVENT_READ_BINARY_DONE = 5; + /** Finished retrieving size of records for linear-fixed EF; now load. */ + static protected final int EVENT_GET_RECORD_SIZE_DONE = 6; + /** Finished loading single record from a linear-fixed EF; post result. */ + static protected final int EVENT_READ_RECORD_DONE = 7; + /** Finished retrieving record size; post result. */ + static protected final int EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE = 8; + /** Finished retrieving image instance record; post result. */ + static protected final int EVENT_READ_IMG_DONE = 9; + /** Finished retrieving icon data; post result. */ + static protected final int EVENT_READ_ICON_DONE = 10; + + // member variables + protected PhoneBase phone; + + static class LoadLinearFixedContext { + + int efid; + int recordNum, recordSize, countRecords; + boolean loadAll; + + Message onLoaded; + + ArrayList results; + + LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) { + this.efid = efid; + this.recordNum = recordNum; + this.onLoaded = onLoaded; + this.loadAll = false; + } + + LoadLinearFixedContext(int efid, Message onLoaded) { + this.efid = efid; + this.recordNum = 1; + this.loadAll = true; + this.onLoaded = onLoaded; + } + } + + /** + * Default constructor + */ + protected IccFileHandler(PhoneBase phone) { + super(); + this.phone = phone; + } + + public void dispose() { + } + + //***** Public Methods + + /** + * Load a record from a SIM Linear Fixed EF + * + * @param fileid EF id + * @param recordNum 1-based (not 0-based) record number + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) { + Message response + = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid, recordNum, onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a image instance record from a SIM Linear Fixed EF-IMG + * + * @param recordNum 1-based (not 0-based) record number + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFImgLinearFixed(int recordNum, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_IMG_DONE, + new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum, + onLoaded)); + + // TODO(): Verify when path changes are done. + phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img", + recordNum, READ_RECORD_MODE_ABSOLUTE, + GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response); + } + + /** + * get record size for a linear fixed EF + * + * @param fileid EF id + * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[] + * int[0] is the record length int[1] is the total length of the EF + * file int[3] is the number of records in the EF file So int[0] * + * int[3] = int[1] + */ + public void getEFLinearRecordSize(int fileid, Message onLoaded) { + Message response + = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid, onLoaded)); + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load all records from a SIM Linear Fixed EF + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is an ArrayList + * + */ + public void loadEFLinearFixedAll(int fileid, Message onLoaded) { + Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid,onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a SIM Transparent EF + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + + public void loadEFTransparent(int fileid, Message onLoaded) { + Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, + fileid, 0, onLoaded); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to + * retrive STK's icon data. + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, + int length, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, + onLoaded); + + phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset, + length, null, null, response); + } + + /** + * Update a record in a linear fixed EF + * @param fileid EF id + * @param recordNum 1-based (not 0-based) record number + * @param data must be exactly as long as the record in the EF + * @param pin2 for CHV2 operations, otherwist must be null + * @param onComplete onComplete.obj will be an AsyncResult + * onComplete.obj.userObj will be a IccIoResult on success + */ + public void updateEFLinearFixed(int fileid, int recordNum, byte[] data, + String pin2, Message onComplete) { + phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid), + recordNum, READ_RECORD_MODE_ABSOLUTE, data.length, + IccUtils.bytesToHexString(data), pin2, onComplete); + } + + /** + * Update a transparent EF + * @param fileid EF id + * @param data must be exactly as long as the EF + */ + public void updateEFTransparent(int fileid, byte[] data, Message onComplete) { + phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid), + 0, 0, data.length, + IccUtils.bytesToHexString(data), null, onComplete); + } + + + //***** Abstract Methods + + + //***** Private Methods + + private void sendResult(Message response, Object result, Throwable ex) { + if (response == null) { + return; + } + + AsyncResult.forMessage(response, result, ex); + + response.sendToTarget(); + } + + //***** Overridden from Handler + + public void handleMessage(Message msg) { + AsyncResult ar; + IccIoResult result; + Message response = null; + String str; + LoadLinearFixedContext lc; + + IccException iccException; + byte data[]; + int size; + int fileid; + int recordNum; + int recordSize[]; + + try { + switch (msg.what) { + case EVENT_READ_IMG_DONE: + ar = (AsyncResult) msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, result.payload, ar.exception); + } + break; + case EVENT_READ_ICON_DONE: + ar = (AsyncResult) msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, result.payload, ar.exception); + } + break; + case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE: + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || + EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + recordSize = new int[3]; + recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + recordSize[2] = recordSize[1] / recordSize[0]; + + sendResult(response, recordSize, null); + break; + case EVENT_GET_RECORD_SIZE_DONE: + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + fileid = lc.efid; + recordNum = lc.recordNum; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + + lc.countRecords = size / lc.recordSize; + + if (lc.loadAll) { + lc.results = new ArrayList(lc.countRecords); + } + + phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid), + lc.recordNum, + READ_RECORD_MODE_ABSOLUTE, + lc.recordSize, null, null, + obtainMessage(EVENT_READ_RECORD_DONE, lc)); + break; + case EVENT_GET_BINARY_SIZE_DONE: + ar = (AsyncResult)msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + + fileid = msg.arg1; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + + phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid), + 0, 0, size, null, null, + obtainMessage(EVENT_READ_BINARY_DONE, + fileid, 0, response)); + break; + + case EVENT_READ_RECORD_DONE: + + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + if (!lc.loadAll) { + sendResult(response, result.payload, null); + } else { + lc.results.add(result.payload); + + lc.recordNum++; + + if (lc.recordNum > lc.countRecords) { + sendResult(response, lc.results, null); + } else { + phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid), + lc.recordNum, + READ_RECORD_MODE_ABSOLUTE, + lc.recordSize, null, null, + obtainMessage(EVENT_READ_RECORD_DONE, lc)); + } + } + + break; + + case EVENT_READ_BINARY_DONE: + ar = (AsyncResult)msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + sendResult(response, result.payload, null); + break; + + }} catch (Exception exc) { + if (response != null) { + sendResult(response, null, exc); + } else { + loge("uncaught exception" + exc); + } + } + } + + /** + * Returns the root path of the EF file. + * i.e returns MasterFile + DFfile as a string. + * Ex: For EF_ADN on a SIM, it will return "3F007F10" + * This function handles only EFids that are common to + * RUIM, SIM, USIM and other types of Icc cards. + * + * @param efId + * @return root path of the file. + */ + protected String getCommonIccEFPath(int efid) { + switch(efid) { + case EF_ADN: + case EF_FDN: + case EF_MSISDN: + case EF_SDN: + case EF_EXT1: + case EF_EXT2: + case EF_EXT3: + return MF_SIM + DF_TELECOM; + + case EF_ICCID: + return MF_SIM; + case EF_IMG: + return MF_SIM + DF_TELECOM + DF_GRAPHICS; + } + return null; + } + + protected abstract String getEFPath(int efid); + protected abstract void logd(String s); + + protected abstract void loge(String s); + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java b/telephony/java/com/android/internal/telephony/IccFileNotFound.java similarity index 72% rename from telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java rename to telephony/java/com/android/internal/telephony/IccFileNotFound.java index 982e2fd8082a3b8584620d1fb925634f8c36e949..915cea688284ed46b903c2ba74a67adaad12d63d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java +++ b/telephony/java/com/android/internal/telephony/IccFileNotFound.java @@ -14,25 +14,21 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class SimFileNotFound extends SimException -{ - SimFileNotFound() - { +public class IccFileNotFound extends IccException { + IccFileNotFound() { } - SimFileNotFound(String s) - { + IccFileNotFound(String s) { super(s); } - SimFileNotFound(int ef) - { - super("SIM EF Not Found 0x" + Integer.toHexString(ef)); + IccFileNotFound(int ef) { + super("ICC EF Not Found 0x" + Integer.toHexString(ef)); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimException.java b/telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java similarity index 57% rename from telephony/java/com/android/internal/telephony/gsm/SimException.java rename to telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java index 1c0daba45a1072c06054d38ff55ea03f49a03d1b..66fcfa9d568d0f8896aaf03794051b2b3cb9a91a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimException.java +++ b/telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java @@ -14,45 +14,17 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class SimException extends Exception -{ - SimException() - { +public class IccFileTypeMismatch extends IccException { + public IccFileTypeMismatch() { } - SimException(String s) - { + public IccFileTypeMismatch(String s) { 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/SimIoResult.java b/telephony/java/com/android/internal/telephony/IccIoResult.java similarity index 67% rename from telephony/java/com/android/internal/telephony/gsm/SimIoResult.java rename to telephony/java/com/android/internal/telephony/IccIoResult.java index 2c4da83eccba63233e8b106a841e58085b3c8da5..a6e0ec365bb3e22f4b14a8dde4cc2be3c7dae9d2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimIoResult.java +++ b/telephony/java/com/android/internal/telephony/IccIoResult.java @@ -14,33 +14,30 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ public class -SimIoResult -{ +IccIoResult { int sw1; int sw2; - byte[] payload; - public SimIoResult(int sw1, int sw2, byte[] payload) - { + public byte[] payload; + + public IccIoResult(int sw1, int sw2, byte[] payload) { this.sw1 = sw1; this.sw2 = sw2; this.payload = payload; } - public SimIoResult(int sw1, int sw2, String hexString) - { - this(sw1, sw2, SimUtils.hexStringToBytes(hexString)); + public IccIoResult(int sw1, int sw2, String hexString) { + this(sw1, sw2, IccUtils.hexStringToBytes(hexString)); } - public String toString() - { - return "SimIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + public String toString() { + return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + Integer.toHexString(sw2); } @@ -49,27 +46,25 @@ SimIoResult * See GSM 11.11 Section 9.4 * (the fun stuff is absent in 51.011) */ - public boolean success() - { + public boolean success() { return sw1 == 0x90 || sw1 == 0x91 || sw1 == 0x9e || sw1 == 0x9f; } /** * Returns exception on error or null if success */ - public SimException getException() - { + public IccException getException() { if (success()) return null; - + switch (sw1) { case 0x94: if (sw2 == 0x08) { - return new SimFileTypeMismatch(); + return new IccFileTypeMismatch(); } else { - return new SimFileNotFound(); + return new IccFileNotFound(); } default: - return new SimException("sw1:" + sw1 + " sw2:" + sw2); + return new IccException("sw1:" + sw1 + " sw2:" + sw2); } } } diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java new file mode 100644 index 0000000000000000000000000000000000000000..0bcaaa684d9bd5fca82da0b6b6da72f45d50357b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java @@ -0,0 +1,266 @@ +/* + * 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.content.pm.PackageManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ServiceManager; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * SimPhoneBookInterfaceManager to provide an inter-process communication to + * access ADN-like SIM records. + */ +public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub { + protected static final boolean DBG = true; + + protected PhoneBase phone; + protected AdnRecordCache adnCache; + protected Object mLock = new Object(); + protected int recordSize[]; + protected boolean success; + protected List records; + + protected static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false; + + protected static final int EVENT_GET_SIZE_DONE = 1; + protected static final int EVENT_LOAD_DONE = 2; + protected static final int EVENT_UPDATE_DONE = 3; + + protected Handler mBaseHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_GET_SIZE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + recordSize = (int[])ar.result; + // recordSize[0] is the record length + // recordSize[1] is the total length of the EF file + // recordSize[2] is the number of records in the EF file + logd("GET_RECORD_SIZE Size " + recordSize[0] + + " total " + recordSize[1] + + " #record " + recordSize[2]); + mLock.notifyAll(); + } + } + break; + case EVENT_UPDATE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + success = (ar.exception == null); + mLock.notifyAll(); + } + break; + case EVENT_LOAD_DONE: + ar = (AsyncResult)msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + records = (List) + ((ArrayList) ar.result); + } else { + if(DBG) logd("Cannot load ADN records"); + if (records != null) { + records.clear(); + } + } + mLock.notifyAll(); + } + break; + } + } + }; + + public IccPhoneBookInterfaceManager(PhoneBase phone) { + this.phone = phone; + } + + public void dispose() { + } + + protected void publish() { + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy + ServiceManager.addService("simphonebook", this); + } + + protected abstract void logd(String msg); + + protected abstract void loge(String msg); + + /** + * Replace oldAdn with newAdn in ADN-like record in EF + * + * getAdnRecordsInEf must be called at least once before this function, + * otherwise an error will be returned + * throws SecurityException if no WRITE_CONTACTS permission + * + * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN + * @param oldTag adn tag to be replaced + * @param oldPhoneNumber adn number to be replaced + * Set both oldTag and oldPhoneNubmer to "" means to replace an + * empty record, aka, insert new record + * @param newTag adn tag to be stored + * @param newPhoneNumber adn number ot be stored + * Set both newTag and newPhoneNubmer to "" means to replace the old + * record with empty one, aka, delete old record + * @param pin2 required to update EF_FDN, otherwise must be null + * @return true for success + */ + public boolean + updateAdnRecordsInEfBySearch (int efid, + String oldTag, String oldPhoneNumber, + String newTag, String newPhoneNumber, String pin2) { + + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.WRITE_CONTACTS permission"); + } + + + if (DBG) logd("updateAdnRecordsInEfBySearch: efid=" + efid + + " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" + + " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); + synchronized(mLock) { + checkThread(); + success = false; + Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE); + AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber); + AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); + adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to update by search"); + } + } + return success; + } + + /** + * Update an ADN-like EF record by record index + * + * This is useful for iteration the whole ADN file, such as write the whole + * phone book or erase/format the whole phonebook + * throws SecurityException if no WRITE_CONTACTS permission + * + * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN + * @param newTag adn tag to be stored + * @param newPhoneNumber adn number to be stored + * Set both newTag and newPhoneNubmer to "" means to replace the old + * record with empty one, aka, delete old record + * @param index is 1-based adn record index to be updated + * @param pin2 required to update EF_FDN, otherwise must be null + * @return true for success + */ + public boolean + updateAdnRecordsInEfByIndex(int efid, String newTag, + String newPhoneNumber, int index, String pin2) { + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.WRITE_CONTACTS permission"); + } + + if (DBG) logd("updateAdnRecordsInEfByIndex: efid=" + efid + + " Index=" + index + " ==> " + + "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); + synchronized(mLock) { + checkThread(); + success = false; + Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE); + AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); + adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to update by index"); + } + } + return success; + } + + /** + * Get the capacity of records in efid + * + * @param efid the EF id of a ADN-like ICC + * @return int[3] array + * recordSizes[0] is the single record length + * recordSizes[1] is the total length of the EF file + * recordSizes[2] is the number of records in the EF file + */ + public abstract int[] getAdnRecordsSize(int efid); + + /** + * Loads the AdnRecords in efid and returns them as a + * List of AdnRecords + * + * throws SecurityException if no READ_CONTACTS permission + * + * @param efid the EF id of a ADN-like ICC + * @return List of AdnRecord + */ + public List getAdnRecordsInEf(int efid) { + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.READ_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.READ_CONTACTS permission"); + } + + if (DBG) logd("getAdnRecordsInEF: efid=" + efid); + + synchronized(mLock) { + checkThread(); + Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE); + adnCache.requestLoadAllAdnLike(efid, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to load from the SIM"); + } + } + return records; + } + + protected void checkThread() { + if (!ALLOW_SIM_OP_IN_UI_THREAD) { + // Make sure this isn't the UI thread, since it will block + if (mBaseHandler.getLooper().equals(Looper.myLooper())) { + loge("query() called on the main UI thread!"); + throw new IllegalStateException( + "You cannot call query on this provder from the main UI thread."); + } + } + } +} + diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..1c0fc52e78eb413f8c90027b7d7197755b20d5f5 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.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 com.android.internal.telephony; + +import android.content.pm.PackageManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ServiceManager; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + + +/** + * SimPhoneBookInterfaceManager to provide an inter-process communication to + * access ADN-like SIM records. + */ +public class IccPhoneBookInterfaceManagerProxy extends IIccPhoneBook.Stub { + private IccPhoneBookInterfaceManager mIccPhoneBookInterfaceManager; + + public IccPhoneBookInterfaceManagerProxy(IccPhoneBookInterfaceManager + iccPhoneBookInterfaceManager) { + mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager; + if(ServiceManager.getService("simphonebook") == null) { + ServiceManager.addService("simphonebook", this); + } + } + + public void setmIccPhoneBookInterfaceManager( + IccPhoneBookInterfaceManager iccPhoneBookInterfaceManager) { + this.mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager; + } + + public boolean + updateAdnRecordsInEfBySearch (int efid, + String oldTag, String oldPhoneNumber, + String newTag, String newPhoneNumber, + String pin2) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfBySearch( + efid, oldTag, oldPhoneNumber, newTag, newPhoneNumber, pin2); + } + + public boolean + updateAdnRecordsInEfByIndex(int efid, String newTag, + String newPhoneNumber, int index, String pin2) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfByIndex(efid, + newTag, newPhoneNumber, index, pin2); + } + + public int[] getAdnRecordsSize(int efid) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.getAdnRecordsSize(efid); + } + + public List getAdnRecordsInEf(int efid) throws android.os.RemoteException { + return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid); + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java similarity index 82% rename from telephony/java/com/android/internal/telephony/gsm/SimProvider.java rename to telephony/java/com/android/internal/telephony/IccProvider.java index cece4ba69d29bcd7183f4bdecc3c35341aefa8dc..4cbd779722d4fa175c80b93031d1801ac1e0800c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimProvider.java +++ b/telephony/java/com/android/internal/telephony/IccProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.content.ContentProvider; import android.content.UriMatcher; @@ -31,11 +31,16 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.IIccPhoneBook; + + /** * {@hide} */ -public class SimProvider extends ContentProvider { - private static final String TAG = "SimProvider"; +public class IccProvider extends ContentProvider { + private static final String TAG = "IccProvider"; private static final boolean DBG = false; @@ -56,9 +61,9 @@ public class SimProvider extends ContentProvider { new UriMatcher(UriMatcher.NO_MATCH); static { - URL_MATCHER.addURI("sim", "adn", ADN); - URL_MATCHER.addURI("sim", "fdn", FDN); - URL_MATCHER.addURI("sim", "sdn", SDN); + URL_MATCHER.addURI("icc", "adn", ADN); + URL_MATCHER.addURI("icc", "fdn", FDN); + URL_MATCHER.addURI("icc", "sdn", SDN); } @@ -81,21 +86,21 @@ public class SimProvider extends ContentProvider { public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) { ArrayList results; - + if (!mSimulator) { switch (URL_MATCHER.match(url)) { case ADN: - results = loadFromEf(SimConstants.EF_ADN); + results = loadFromEf(IccConstants.EF_ADN); break; - + case FDN: - results = loadFromEf(SimConstants.EF_FDN); + results = loadFromEf(IccConstants.EF_FDN); break; - + case SDN: - results = loadFromEf(SimConstants.EF_SDN); + results = loadFromEf(IccConstants.EF_SDN); break; - + default: throw new IllegalArgumentException("Unknown URL " + url); } @@ -152,11 +157,11 @@ public class SimProvider extends ContentProvider { int match = URL_MATCHER.match(url); switch (match) { case ADN: - efType = SimConstants.EF_ADN; + efType = IccConstants.EF_ADN; break; case FDN: - efType = SimConstants.EF_FDN; + efType = IccConstants.EF_FDN; pin2 = initialValues.getAsString("pin2"); break; @@ -167,7 +172,7 @@ public class SimProvider extends ContentProvider { String tag = initialValues.getAsString("tag"); String number = initialValues.getAsString("number"); - boolean success = addSimRecordToEf(efType, tag, number, pin2); + boolean success = addIccRecordToEf(efType, tag, number, pin2); if (!success) { return null; @@ -183,7 +188,7 @@ public class SimProvider extends ContentProvider { buf.append("fdn/"); break; } - + // TODO: we need to find out the rowId for the newly added record buf.append(0); @@ -218,11 +223,11 @@ public class SimProvider extends ContentProvider { int match = URL_MATCHER.match(url); switch (match) { case ADN: - efType = SimConstants.EF_ADN; + efType = IccConstants.EF_ADN; break; case FDN: - efType = SimConstants.EF_FDN; + efType = IccConstants.EF_FDN; break; default: @@ -269,7 +274,7 @@ public class SimProvider extends ContentProvider { return 0; } - boolean success = deleteSimRecordFromEf(efType, tag, number, pin2); + boolean success = deleteIccRecordFromEf(efType, tag, number, pin2); if (!success) { return 0; } @@ -287,11 +292,11 @@ public class SimProvider extends ContentProvider { int match = URL_MATCHER.match(url); switch (match) { case ADN: - efType = SimConstants.EF_ADN; + efType = IccConstants.EF_ADN; break; case FDN: - efType = SimConstants.EF_FDN; + efType = IccConstants.EF_FDN; pin2 = values.getAsString("pin2"); break; @@ -305,7 +310,7 @@ public class SimProvider extends ContentProvider { String newTag = values.getAsString("newTag"); String newNumber = values.getAsString("newNumber"); - boolean success = updateSimRecordInEf(efType, tag, number, + boolean success = updateIccRecordInEf(efType, tag, number, newTag, newNumber, pin2); if (!success) { @@ -322,17 +327,16 @@ public class SimProvider extends ContentProvider { if (DBG) log("loadFromEf: efType=" + efType); try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - adnRecords = simIpb.getAdnRecordsInEf(efType); + if (iccIpb != null) { + adnRecords = iccIpb.getAdnRecordsInEf(efType); } } catch (RemoteException ex) { // ignore it } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - if (adnRecords != null) { // Load the results @@ -351,8 +355,8 @@ public class SimProvider extends ContentProvider { } private boolean - addSimRecordToEf(int efType, String name, String number, String pin2) { - if (DBG) log("addSimRecordToEf: efType=" + efType + ", name=" + name + + addIccRecordToEf(int efType, String name, String number, String pin2) { + if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name + ", number=" + number); boolean success = false; @@ -361,11 +365,12 @@ public class SimProvider extends ContentProvider { // updateAdnRecordsInEfBySearch()? In any case, we will leave // the UI level logic to fill that prereq if necessary. But // hopefully, we can remove this requirement. + try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - success = simIpb.updateAdnRecordsInEfBySearch(efType, "", "", + if (iccIpb != null) { + success = iccIpb.updateAdnRecordsInEfBySearch(efType, "", "", name, number, pin2); } } catch (RemoteException ex) { @@ -373,23 +378,23 @@ public class SimProvider extends ContentProvider { } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - if (DBG) log("addSimRecordToEf: " + success); + if (DBG) log("addIccRecordToEf: " + success); return success; } private boolean - updateSimRecordInEf(int efType, String oldName, String oldNumber, + updateIccRecordInEf(int efType, String oldName, String oldNumber, String newName, String newNumber,String pin2) { - if (DBG) log("updateSimRecordInEf: efType=" + efType + + if (DBG) log("updateIccRecordInEf: efType=" + efType + ", oldname=" + oldName + ", oldnumber=" + oldNumber + ", newname=" + newName + ", newnumber=" + newNumber); boolean success = false; try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - success = simIpb.updateAdnRecordsInEfBySearch(efType, + if (iccIpb != null) { + success = iccIpb.updateAdnRecordsInEfBySearch(efType, oldName, oldNumber, newName, newNumber, pin2); } } catch (RemoteException ex) { @@ -397,34 +402,30 @@ public class SimProvider extends ContentProvider { } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - - if (DBG) log("updateSimRecordInEf: " + success); + if (DBG) log("updateIccRecordInEf: " + success); return success; } - private boolean deleteSimRecordFromEf(int efType, - String name, String number, - String pin2) { - if (DBG) log("deleteSimRecordFromEf: efType=" + efType + + private boolean deleteIccRecordFromEf(int efType, String name, String number, String pin2) { + if (DBG) log("deleteIccRecordFromEf: efType=" + efType + ", name=" + name + ", number=" + number + ", pin2=" + pin2); boolean success = false; try { - ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface( + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( ServiceManager.getService("simphonebook")); - if (simIpb != null) { - success = simIpb.updateAdnRecordsInEfBySearch(efType, - name, number, "", "", pin2); + if (iccIpb != null) { + success = iccIpb.updateAdnRecordsInEfBySearch(efType, + name, number, "", "", pin2); } } catch (RemoteException ex) { // ignore it } catch (SecurityException ex) { if (DBG) log(ex.toString()); } - - if (DBG) log("deleteSimRecordFromEf: " + success); + if (DBG) log("deleteIccRecordFromEf: " + success); return success; } @@ -449,7 +450,7 @@ public class SimProvider extends ContentProvider { } private void log(String msg) { - Log.d(TAG, "[SimProvider] " + msg); + Log.d(TAG, "[IccProvider] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java new file mode 100644 index 0000000000000000000000000000000000000000..114094b74181fbad0cbf4f13b142325d7813448f --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccRecords.java @@ -0,0 +1,237 @@ +/* + * 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.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.util.Log; + +import java.util.ArrayList; + +/** + * {@hide} + */ +public abstract class IccRecords extends Handler implements IccConstants { + + protected static final boolean DBG = true; + //***** Instance Variables + + protected PhoneBase phone; + protected RegistrantList recordsLoadedRegistrants = new RegistrantList(); + + protected int recordsToLoad; // number of pending load requests + + protected AdnRecordCache adnCache; + + //***** Cached SIM State; cleared on channel close + + protected boolean recordsRequested = false; // true if we've made requests for the sim records + + public String iccid; + protected String msisdn = null; // My mobile number + protected String msisdnTag = null; + protected String voiceMailNum = null; + protected String voiceMailTag = null; + protected String newVoiceMailNum = null; + protected String newVoiceMailTag = null; + protected boolean isVoiceMailFixed = false; + protected int countVoiceMessages = 0; + + protected int mncLength = 0; // 0 is used to indicate that the value + // is not initialized + protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated + + protected String spn; + protected int spnDisplayCondition; + + //***** Constants + + // Bitmasks for SPN display rules. + protected static final int SPN_RULE_SHOW_SPN = 0x01; + protected static final int SPN_RULE_SHOW_PLMN = 0x02; + + //***** Event Constants + protected static final int EVENT_SET_MSISDN_DONE = 30; + + //***** Constructor + + public IccRecords(PhoneBase p) { + this.phone = p; + } + + protected abstract void onRadioOffOrNotAvailable(); + + //***** Public Methods + public AdnRecordCache getAdnCache() { + return adnCache; + } + + public void registerForRecordsLoaded(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + recordsLoadedRegistrants.add(r); + + if (recordsToLoad == 0 && recordsRequested == true) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + + public void unregisterForRecordsLoaded(Handler h) { + recordsLoadedRegistrants.remove(h); + } + + public String getMsisdnNumber() { + return msisdn; + } + + /** + * Set subscriber number to SIM record + * + * The subscriber number is stored in EF_MSISDN (TS 51.011) + * + * When the operation is complete, onComplete will be sent to its handler + * + * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) + * @param number dailing nubmer (up to 20 digits) + * if the number starts with '+', then set to international TOA + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void setMsisdnNumber(String alphaTag, String number, + Message onComplete) { + + msisdn = number; + msisdnTag = alphaTag; + + if(DBG) log("Set MSISDN: " + msisdnTag +" " + msisdn); + + + AdnRecord adn = new AdnRecord(msisdnTag, msisdn); + + new AdnRecordLoader(phone).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null, + obtainMessage(EVENT_SET_MSISDN_DONE, onComplete)); + } + + public String getMsisdnAlphaTag() { + return msisdnTag; + } + + public String getVoiceMailNumber() { + return voiceMailNum; + } + + /** + * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41) + * @return null if SIM is not yet ready or no RUIM entry + */ + public String getServiceProviderName() { + return spn; + } + + /** + * Set voice mail number to SIM record + * + * The voice mail number can be stored either in EF_MBDN (TS 51.011) or + * EF_MAILBOX_CPHS (CPHS 4.2) + * + * If EF_MBDN is available, store the voice mail number to EF_MBDN + * + * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS + * + * So the voice mail number will be stored in both EFs if both are available + * + * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail. + * + * When the operation is complete, onComplete will be sent to its handler + * + * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters) + * @param voiceNumber dailing nubmer (upto 20 digits) + * if the number is start with '+', then set to international TOA + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber, + Message onComplete); + + public String getVoiceMailAlphaTag() { + return voiceMailTag; + } + + /** + * Sets the SIM voice message waiting indicator records + * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported + * @param countWaiting The number of messages waiting, if known. Use + * -1 to indicate that an unknown number of + * messages are waiting + */ + public abstract void setVoiceMessageWaiting(int line, int countWaiting); + + /** @return true if there are messages waiting, false otherwise. */ + public boolean getVoiceMessageWaiting() { + return countVoiceMessages != 0; + } + + /** + * Returns number of voice messages waiting, if available + * If not available (eg, on an older CPHS SIM) -1 is returned if + * getVoiceMessageWaiting() is true + */ + public int getCountVoiceMessages() { + return countVoiceMessages; + } + + /** + * Called by STK Service when REFRESH is received. + * @param fileChanged indicates whether any files changed + * @param fileList if non-null, a list of EF files that changed + */ + public abstract void onRefresh(boolean fileChanged, int[] fileList); + + + public boolean getRecordsLoaded() { + if (recordsToLoad == 0 && recordsRequested == true) { + return true; + } else { + return false; + } + } + + //***** Overridden from Handler + public abstract void handleMessage(Message msg); + + protected abstract void onRecordLoaded(); + + protected abstract void onAllRecordsLoaded(); + + /** + * Returns the SpnDisplayRule based on settings on the SIM and the + * specified plmn (currently-registered PLMN). See TS 22.101 Annex A + * and TS 51.011 10.3.11 for details. + * + * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. + */ + protected abstract int getDisplayRule(String plmn); + + protected abstract void log(String s); +} + diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java new file mode 100644 index 0000000000000000000000000000000000000000..620f2deae500a7a095481e4c496ee8d0126ac16b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -0,0 +1,166 @@ +/* + * 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.app.PendingIntent; +import android.content.Context; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; + +/** + * IccSmsInterfaceManager to provide an inter-process communication to + * access Sms in Icc. + */ +public abstract class IccSmsInterfaceManager extends ISms.Stub { + static final boolean DBG = true; + + protected PhoneBase mPhone; + protected Context mContext; + protected SMSDispatcher mDispatcher; + + protected IccSmsInterfaceManager(PhoneBase phone){ + mPhone = phone; + mContext = phone.getContext(); + } + + protected void enforceReceiveAndSend(String message) { + mContext.enforceCallingPermission( + "android.permission.RECEIVE_SMS", message); + mContext.enforceCallingPermission( + "android.permission.SEND_SMS", message); + } + + /** + * Send a Raw PDU SMS + * + * @param smsc the SMSC to send the message through, or NULL for the + * defatult SMSC + * @param pdu the raw PDU to send + * @param sentIntent if not NULL this Intent is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * @param deliveryIntent if not NULL this Intent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + */ + public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.SEND_SMS", + "Sending SMS message"); + if (DBG) log("sendRawPdu: smsc=" + smsc + + " pdu="+ pdu + " sentIntent" + sentIntent + + " deliveryIntent" + deliveryIntent); + mDispatcher.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + + /** + * Send a multi-part text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an ArrayList of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * @param deliveryIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + */ + public void sendMultipartText(String destinationAddress, String scAddress, List parts, + List sentIntents, List deliveryIntents) { + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.SEND_SMS", + "Sending SMS message"); + if (DBG) log("sendMultipartText"); + mDispatcher.sendMultipartText(destinationAddress, scAddress, (ArrayList) parts, + (ArrayList) sentIntents, (ArrayList) deliveryIntents); + } + + /** + * create SmsRawData lists from all sms record byte[] + * Use null to indicate "free" record + * + * @param messages List of message records from EF_SMS. + * @return SmsRawData list of all in-used records + */ + protected ArrayList buildValidRawData(ArrayList messages) { + int count = messages.size(); + ArrayList ret; + + ret = new ArrayList(count); + + for (int i = 0; i < count; i++) { + byte[] ba = messages.get(i); + if (ba[0] == STATUS_ON_ICC_FREE) { + ret.add(null); + } else { + ret.add(new SmsRawData(messages.get(i))); + } + } + + return ret; + } + + /** + * Generates an EF_SMS record from status and raw PDU. + * + * @param status Message status. See TS 51.011 10.5.3. + * @param pdu Raw message PDU. + * @return byte array for the record. + */ + protected byte[] makeSmsRecordData(int status, byte[] pdu) { + byte[] data = new byte[IccConstants.SMS_RECORD_LENGTH]; + + // Status bits for this record. See TS 51.011 10.5.3 + data[0] = (byte)(status & 7); + + System.arraycopy(pdu, 0, data, 1, pdu.length); + + // Pad out with 0xFF's. + for (int j = pdu.length+1; j < IccConstants.SMS_RECORD_LENGTH; j++) { + data[j] = -1; + } + + return data; + } + + protected abstract void log(String msg); + +} + diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..a51d074104c779cfd03cc0c7afb9bdf8bbd977fa --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.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 com.android.internal.telephony; + +import android.app.PendingIntent; +import android.os.ServiceManager; + +import java.util.List; + +public class IccSmsInterfaceManagerProxy extends ISms.Stub { + private IccSmsInterfaceManager mIccSmsInterfaceManager; + + public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager + iccSmsInterfaceManager) { + this.mIccSmsInterfaceManager = iccSmsInterfaceManager; + if(ServiceManager.getService("isms") == null) { + ServiceManager.addService("isms", this); + } + } + + public void setmIccSmsInterfaceManager(IccSmsInterfaceManager iccSmsInterfaceManager) { + this.mIccSmsInterfaceManager = iccSmsInterfaceManager; + } + + public boolean + updateMessageOnIccEf(int index, int status, byte[] pdu) throws android.os.RemoteException { + return mIccSmsInterfaceManager.updateMessageOnIccEf(index, status, pdu); + } + + public boolean copyMessageToIccEf(int status, byte[] pdu, + byte[] smsc) throws android.os.RemoteException { + return mIccSmsInterfaceManager.copyMessageToIccEf(status, pdu, smsc); + } + + public List getAllMessagesFromIccEf() throws android.os.RemoteException { + return mIccSmsInterfaceManager.getAllMessagesFromIccEf(); + } + + public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) throws android.os.RemoteException { + mIccSmsInterfaceManager.sendRawPdu(smsc, pdu, sentIntent, + deliveryIntent); + } + + public void sendMultipartText(String destinationAddress, String scAddress, + List parts, List sentIntents, + List deliveryIntents) throws android.os.RemoteException { + mIccSmsInterfaceManager.sendMultipartText(destinationAddress, scAddress, + parts, sentIntents, deliveryIntents); + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java similarity index 90% rename from telephony/java/com/android/internal/telephony/gsm/SimUtils.java rename to telephony/java/com/android/internal/telephony/IccUtils.java index 2eecdba06f52b774e1ecb528b1fdb46efec92be4..881ed2dd2d7c380509ae4dd751b1e24e63525f93 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -14,48 +14,48 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; - -import java.io.UnsupportedEncodingException; +package com.android.internal.telephony; import android.graphics.Bitmap; import android.graphics.Color; import android.util.Log; +import com.android.internal.telephony.GsmAlphabet; + +import java.io.UnsupportedEncodingException; + /** * Various methods, useful for dealing with SIM data. */ -public class SimUtils -{ - static final String LOG_TAG="GSM"; +public class IccUtils { + static final String LOG_TAG="IccUtils"; /** * Many fields in GSM SIM's are stored as nibble-swizzled BCD * - * Assumes left-justified field that may be padded right with 0xf + * Assumes left-justified field that may be padded right with 0xf * values. * * Stops on invalid BCD value, returning string so far */ public static String - bcdToString(byte[] data, int offset, int length) - { + bcdToString(byte[] data, int offset, int length) { StringBuilder ret = new StringBuilder(length*2); - + for (int i = offset ; i < offset + length ; i++) { byte b; int v; - + v = data[i] & 0xf; if (v > 9) break; ret.append((char)('0' + v)); v = (data[i] >> 4) & 0xf; if (v > 9) break; - ret.append((char)('0' + v)); + ret.append((char)('0' + v)); } - - return ret.toString(); + + return ret.toString(); } @@ -66,7 +66,7 @@ public class SimUtils * significant nibble. * * Out-of-range digits are treated as 0 for the sake of the time stamp, - * because of this: + * because of this: * * TS 23.040 section 9.2.3.11 * "if the MS receives a non-integer value in the SCTS, it shall @@ -74,13 +74,12 @@ public class SimUtils * exactly as received" */ public static int - bcdByteToInt(byte b) - { + bcdByteToInt(byte b) { int ret = 0; // treat out-of-range BCD values as 0 if ((b & 0xf0) <= 0x90) { - ret = (b >> 4) & 0xf; + ret = (b >> 4) & 0xf; } if ((b & 0x0f) <= 0x09) { @@ -90,6 +89,24 @@ public class SimUtils return ret; } + /** Decodes BCD byte like {@link bcdByteToInt}, but the most significant BCD + * digit is expected in the most significant nibble. + */ + public static int + beBcdByteToInt(byte b) { + int ret = 0; + + // treat out-of-range BCD values as 0 + if ((b & 0xf0) <= 0x90) { + ret = ((b >> 4) & 0xf) * 10; + } + + if ((b & 0x0f) <= 0x09) { + ret += (b & 0xf); + } + + return ret; + } /** * Decodes a string field that's formatted like the EF[ADN] alpha @@ -97,11 +114,11 @@ public class SimUtils * * From TS 51.011 10.5.1: * Coding: - * this alpha tagging shall use either - * - the SMS default 7 bit coded alphabet as defined in - * TS 23.038 [12] with bit 8 set to 0. The alpha identifier + * this alpha tagging shall use either + * - the SMS default 7 bit coded alphabet as defined in + * TS 23.038 [12] with bit 8 set to 0. The alpha identifier * shall be left justified. Unused bytes shall be set to 'FF'; or - * - one of the UCS2 coded options as defined in annex B. + * - one of the UCS2 coded options as defined in annex B. * * Annex B from TS 11.11 V8.13.0: * 1) If the first octet in the alpha string is '80', then the @@ -109,7 +126,7 @@ public class SimUtils * 2) if the first octet in the alpha string is '81', then the * second octet contains a value indicating the number of * characters in the string, and the third octet contains an - * 8 bit number which defines bits 15 to 8 of a 16 bit + * 8 bit number which defines bits 15 to 8 of a 16 bit * base pointer, where bit 16 is set to zero and bits 7 to 1 * are also set to zero. These sixteen bits constitute a * base pointer to a "half page" in the UCS2 code space, to be @@ -127,8 +144,7 @@ public class SimUtils * base pointer to a "half page" in the UCS2 code space... */ public static String - adnStringFieldToString(byte[] data, int offset, int length) - { + adnStringFieldToString(byte[] data, int offset, int length) { if (length >= 1) { if (data[offset] == (byte) 0x80) { int ucslen = (length - 1) / 2; @@ -208,8 +224,7 @@ public class SimUtils } static int - hexCharToInt(char c) - { + hexCharToInt(char c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'A' && c <= 'F') return (c - 'A' + 10); if (c >= 'a' && c <= 'f') return (c - 'a' + 10); @@ -219,17 +234,16 @@ public class SimUtils /** * Converts a hex String to a byte array. - * + * * @param s A string of hexadecimal characters, must be an even number of * chars long * * @return byte array representation - * + * * @throws RuntimeException on invalid format */ public static byte[] - hexStringToBytes(String s) - { + hexStringToBytes(String s) { byte[] ret; if (s == null) return null; @@ -239,10 +253,10 @@ public class SimUtils ret = new byte[sz/2]; for (int i=0 ; i *

          *
        • IDLE = no phone activity
        • - *
        • RINGING = a phone call is ringing or call waiting. + *
        • RINGING = a phone call is ringing or call waiting. * In the latter case, another call is active as well
        • *
        • OFFHOOK = The phone is off hook. At least one call * exists that is dialing, active or holding and no calls are @@ -70,7 +74,7 @@ public interface Phone { CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED; }; - enum DataActivityState { + public enum DataActivityState { /** * The state of a data activity. *
            @@ -109,9 +113,12 @@ public interface Phone { static final String APN_TYPE_DEFAULT = "default"; /** APN type for MMS traffic */ static final String APN_TYPE_MMS = "mms"; + /** APN type for SUPL assisted GPS */ + static final String APN_TYPE_SUPL = "supl"; // "Features" accessible through the connectivity manager static final String FEATURE_ENABLE_MMS = "enableMMS"; + static final String FEATURE_ENABLE_SUPL = "enableSUPL"; /** * Return codes for enableApnType() @@ -131,6 +138,8 @@ public interface Phone { static final String REASON_DATA_ENABLED = "dataEnabled"; static final String REASON_GPRS_ATTACHED = "gprsAttached"; static final String REASON_GPRS_DETACHED = "gprsDetached"; + static final String REASON_CDMA_DATA_ATTACHED = "cdmaDataAttached"; + static final String REASON_CDMA_DATA_DETACHED = "cdmaDataDetached"; static final String REASON_APN_CHANGED = "apnChanged"; static final String REASON_APN_SWITCHED = "apnSwitched"; static final String REASON_RESTORE_DEFAULT_APN = "restoreDefaultApn"; @@ -152,12 +161,32 @@ public interface Phone { static final int BM_BOUNDARY = 6; // upper band boundary // Used for preferred network type - static final int NT_AUTO_TYPE = 0; // WCDMA preferred (auto mode) - static final int NT_GSM_TYPE = 1; // GSM only - static final int NT_WCDMA_TYPE = 2; // WCDMA only - - /** - * Get the current ServiceState. Use + // Note NT_* substitute RILConstants.NETWORK_MODE_* above the Phone + int NT_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ + int NT_MODE_GSM_ONLY = 1; /* GSM only */ + int NT_MODE_WCDMA_ONLY = 2; /* WCDMA only */ + int NT_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NT_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NT_MODE_CDMA_NO_EVDO = 5; /* CDMA only */ + int NT_MODE_EVDO_NO_CDMA = 6; /* EvDo only */ + int NT_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int PREFERRED_NT_MODE = NT_MODE_GSM_ONLY; + + + // Used for CDMA roaming mode + static final int CDMA_RM_HOME = 0; //Home Networks only, as defined in PRL + static final int CDMA_RM_AFFILIATED = 1; //Roaming an Affiliated networks, as defined in PRL + static final int CDMA_RM_ANY = 2; //Roaming on Any Network, as defined in PRL + + // Used for CDMA subscription mode + static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; //RUIM/SIM (default) + static final int CDMA_SUBSCRIPTION_NV = 1; //NV -> non-volatile memory + + /** + * Get the current ServiceState. Use * registerForServiceStateChanged to be informed of * updates. */ @@ -167,11 +196,12 @@ public interface Phone { * Get the current CellLocation. */ CellLocation getCellLocation(); - + /** * Get the current DataState. No change notification exists at this - * interface -- use - * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} instead. + * interface -- use + * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} + * instead. */ DataState getDataConnectionState(); @@ -181,58 +211,70 @@ public interface Phone { * {@link TelephonyManager} instead. */ DataActivityState getDataActivityState(); - + /** * Gets the context for the phone, as set at initialization time. */ Context getContext(); - /** + /** + * Disables the DNS check (i.e., allows "0.0.0.0"). + * Useful for lab testing environment. + * @param b true disables the check, false enables. + */ + void disableDnsCheck(boolean b); + + /** + * Returns true if the DNS check is currently disabled. + */ + boolean isDnsCheckDisabled(); + + /** * Get current coarse-grained voice call state. - * Use {@link #registerForPhoneStateChanged(Handler, int, Object) + * Use {@link #registerForPhoneStateChanged(Handler, int, Object) * registerForPhoneStateChanged()} for change notification.

            * If the phone has an active call and call waiting occurs, * then the phone state is RINGING not OFFHOOK - * Note: + * Note: * This registration point provides notification of finer-grained * changes.

            * */ State getState(); - /** + /** * Returns a string identifier for this phone interface for parties * outside the phone app process. * @return The string name. */ String getPhoneName(); - /** + /** * Returns an array of string identifiers for the APN types serviced by the * currently active or last connected APN. * @return The string array. */ String[] getActiveApnTypes(); - - /** + + /** * Returns a string identifier for currently active or last connected APN. * @return The string name. */ String getActiveApn(); - - /** + + /** * Get current signal strength. No change notification available on this * interface. Use PhoneStateNotifier or an equivalent. - * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). + * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). * The following special values are defined:

            *
            • 0 means "-113 dBm or less".
            • *
            • 31 means "-51 dBm or greater".
            - * + * * @return Current signal strength in ASU's. */ int getSignalStrengthASU(); - - /** + + /** * Notifies when a previously untracked non-ringing/waiting connection has appeared. * This is likely due to some other entity (eg, SIM card application) initiating a call. */ @@ -243,7 +285,7 @@ public interface Phone { */ void unregisterForUnknownConnection(Handler h); - /** + /** * Notifies when any aspect of the voice call state changes. * Resulting events will have an AsyncResult in Message.obj. * AsyncResult.userData will be set to the obj argument here. @@ -252,13 +294,13 @@ public interface Phone { void registerForPhoneStateChanged(Handler h, int what, Object obj); /** - * Unregisters for voice call state change notifications. + * Unregisters for voice call state change notifications. * Extraneous calls are tolerated silently. */ void unregisterForPhoneStateChanged(Handler h); - /** + /** * Notifies when a new ringing or waiting connection has appeared.

            * * Messages received from this: @@ -267,19 +309,19 @@ public interface Phone { * AsyncResult.result = a Connection.

            * Please check Connection.isRinging() to make sure the Connection * has not dropped since this message was posted. - * If Connection.isRinging() is true, then + * If Connection.isRinging() is true, then * Connection.getCall() == Phone.getRingingCall() */ void registerForNewRingingConnection(Handler h, int what, Object obj); /** - * Unregisters for new ringing connection notification. + * Unregisters for new ringing connection notification. * Extraneous calls are tolerated silently */ void unregisterForNewRingingConnection(Handler h); - /** + /** * Notifies when an incoming call rings.

            * * Messages received from this: @@ -288,29 +330,29 @@ public interface Phone { * AsyncResult.result = a Connection.

            */ void registerForIncomingRing(Handler h, int what, Object obj); - + /** - * Unregisters for ring notification. + * Unregisters for ring notification. * Extraneous calls are tolerated silently */ - + void unregisterForIncomingRing(Handler h); - - - /** + + + /** * Notifies when a voice connection has disconnected, either due to local * or remote hangup or error. - * + * * Messages received from this will have the following members:

            *

            • Message.obj will be an AsyncResult
            • *
            • AsyncResult.userObj = obj
            • - *
            • AsyncResult.result = a Connection object that is + *
            • AsyncResult.result = a Connection object that is * no longer connected.
            */ void registerForDisconnect(Handler h, int what, Object obj); /** - * Unregisters for voice disconnection notification. + * Unregisters for voice disconnection notification. * Extraneous calls are tolerated silently */ void unregisterForDisconnect(Handler h); @@ -330,7 +372,7 @@ public interface Phone { void registerForMmiInitiate(Handler h, int what, Object obj); /** - * Unregisters for new MMI initiate notification. + * Unregisters for new MMI initiate notification. * Extraneous calls are tolerated silently */ void unregisterForMmiInitiate(Handler h); @@ -346,7 +388,7 @@ public interface Phone { void registerForMmiComplete(Handler h, int what, Object obj); /** - * Unregisters for MMI complete notification. + * Unregisters for MMI complete notification. * Extraneous calls are tolerated silently */ void unregisterForMmiComplete(Handler h); @@ -355,7 +397,7 @@ public interface Phone { * Returns a list of MMI codes that are pending. (They have initiated * but have not yet completed). * Presently there is only ever one. - * Use registerForMmiInitiate + * Use registerForMmiInitiate * and registerForMmiComplete for change notification. */ public List getPendingMmiCodes(); @@ -370,14 +412,14 @@ public interface Phone { public void sendUssdResponse(String ussdMessge); /** - * Register for ServiceState changed. + * Register for ServiceState changed. * Message.obj will contain an AsyncResult. * AsyncResult.result will be a ServiceState instance */ void registerForServiceStateChanged(Handler h, int what, Object obj); /** - * Unregisters for ServiceStateChange notification. + * Unregisters for ServiceStateChange notification. * Extraneous calls are tolerated silently */ void unregisterForServiceStateChanged(Handler h); @@ -394,9 +436,9 @@ public interface Phone { void registerForSuppServiceNotification(Handler h, int what, Object obj); /** - * Unregisters for Supplementary Service notifications. + * Unregisters for Supplementary Service notifications. * Extraneous calls are tolerated silently - * + * * @param h Handler to be removed from the registrant list. */ void unregisterForSuppServiceNotification(Handler h); @@ -414,53 +456,85 @@ public interface Phone { /** * Unregister for notifications when a supplementary service attempt fails. * Extraneous calls are tolerated silently - * + * * @param h Handler to be removed from the registrant list. */ void unregisterForSuppServiceFailed(Handler h); - /** - * Returns SIM record load state. Use + /** + * Register for notifications when a sInCall VoicePrivacy is enabled + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj); + + /** + * Unegister for notifications when a sInCall VoicePrivacy is enabled + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForInCallVoicePrivacyOn(Handler h); + + /** + * Register for notifications when a sInCall VoicePrivacy is disabled + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj); + + /** + * Unegister for notifications when a sInCall VoicePrivacy is disabled + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForInCallVoicePrivacyOff(Handler h); + + /** + * Returns SIM record load state. Use * getSimCard().registerForReady() for change notification. * - * @return true if records from the SIM have been loaded and are + * @return true if records from the SIM have been loaded and are * available (if applicable). If not applicable to the underlying * technology, returns true as well. */ - boolean getSimRecordsLoaded(); + boolean getIccRecordsLoaded(); /** - * Returns the SIM card interface for this phone, or null + * Returns the ICC card interface for this phone, or null * if not applicable to underlying technology. */ - SimCard getSimCard(); + IccCard getIccCard(); /** - * Answers a ringing or waiting call. Active calls, if any, go on hold. + * Answers a ringing or waiting call. Active calls, if any, go on hold. * Answering occurs asynchronously, and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ void acceptCall() throws CallStateException; - /** - * Reject (ignore) a ringing call. In GSM, this means UDUB - * (User Determined User Busy). Reject occurs asynchronously, - * and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + /** + * Reject (ignore) a ringing call. In GSM, this means UDUB + * (User Determined User Busy). Reject occurs asynchronously, + * and final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ void rejectCall() throws CallStateException; - /** + /** * Places any active calls on hold, and makes any held calls * active. Switch occurs asynchronously and may fail. - * Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * Final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException if a call is ringing, waiting, or @@ -469,23 +543,39 @@ public interface Phone { void switchHoldingAndActive() throws CallStateException; /** - * Whether or not the phone can conference in the current phone + * Whether or not the phone can conference in the current phone * state--that is, one call holding and one call active. - * @return true if the phone can conference; false otherwise. + * @return true if the phone can conference; false otherwise. */ boolean canConference(); /** - * Conferences holding and active. Conference occurs asynchronously - * and may fail. Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. - * + * Conferences holding and active. Conference occurs asynchronously + * and may fail. Final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPhoneStateChanged()}. + * * @exception CallStateException if canConference() would return false. * In these cases, this operation may not be performed. */ void conference() throws CallStateException; + /** + * Enable or disable enhanced Voice Privacy (VP). If enhanced VP is + * disabled, normal VP is enabled. + * + * @param enable whether true or false to enable or disable. + * @param onComplete a callback message when the action is completed. + */ + void enableEnhancedVoicePrivacy(boolean enable, Message onComplete); + + /** + * Get the currently set Voice Privacy (VP) mode. + * + * @param onComplete a callback message when the action is completed. + */ + void getEnhancedVoicePrivacy(Message onComplete); + /** * Whether or not the phone can do explicit call transfer in the current * phone state--that is, one call holding and one call active. @@ -513,65 +603,65 @@ public interface Phone { void clearDisconnected(); - /** - * Gets the foreground call object, which represents all connections that - * are dialing or active (all connections + /** + * Gets the foreground call object, which represents all connections that + * are dialing or active (all connections * that have their audio path connected).

            * * The foreground call is a singleton object. It is constant for the life * of this phone. It is never null.

            - * + * * The foreground call will only ever be in one of these states: - * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. + * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getForegroundCall(); - /** + /** * Gets the background call object, which represents all connections that * are holding (all connections that have been accepted or connected, but * do not have their audio path connected).

            * * The background call is a singleton object. It is constant for the life * of this phone object . It is never null.

            - * + * * The background call will only ever be in one of these states: * IDLE, HOLDING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getBackgroundCall(); - /** - * Gets the ringing call object, which represents an incoming + /** + * Gets the ringing call object, which represents an incoming * connection (if present) that is pending answer/accept. (This connection * may be RINGING or WAITING, and there may be only one.)

            * The ringing call is a singleton object. It is constant for the life * of this phone. It is never null.

            - * + * * The ringing call will only ever be in one of these states: * IDLE, INCOMING, WAITING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getRingingCall(); - /** + /** * Initiate a new voice connection. This happens asynchronously, so you * cannot assume the audio path is connected (or a call index has been * assigned) until PhoneStateChanged notification has occurred. * * @exception CallStateException if a new outgoing call is not currently - * possible because no more call slots exist or a call exists that is - * dialing, alerting, ringing, or waiting. Other errors are + * possible because no more call slots exist or a call exists that is + * dialing, alerting, ringing, or waiting. Other errors are * handled asynchronously. */ Connection dial(String dialString) throws CallStateException; @@ -579,7 +669,7 @@ public interface Phone { /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated * without SEND (so dial is not appropriate). - * + * * @param dialString the MMI command to be executed. * @return true if MMI command is executed. */ @@ -597,7 +687,7 @@ public interface Phone { boolean handleInCallMmiCommands(String command) throws CallStateException; /** - * Play a DTMF tone on the active call. Ignored if there is no active call. + * Play a DTMF tone on the active call. Ignored if there is no active call. * @param c should be one of 0-9, '*' or '#'. Other values will be * silently ignored. */ @@ -619,20 +709,20 @@ public interface Phone { /** - * Sets the radio power on/off state (off is sometimes - * called "airplane mode"). Current state can be gotten via - * {@link #getServiceState()}.{@link + * Sets the radio power on/off state (off is sometimes + * called "airplane mode"). Current state can be gotten via + * {@link #getServiceState()}.{@link * android.telephony.ServiceState#getState() getState()}. - * Note: This request is asynchronous. + * Note: This request is asynchronous. * getServiceState().getState() will not change immediately after this call. - * registerForServiceStateChanged() to find out when the + * registerForServiceStateChanged() to find out when the * request is complete. * - * @param power true means "on", false means "off". + * @param power true means "on", false means "off". */ void setRadioPower(boolean power); - /** + /** * Get voice message waiting indicator status. No change notification * available on this interface. Use PhoneStateNotifier or similar instead. * @@ -674,8 +764,8 @@ public interface Phone { void setLine1Number(String alphaTag, String number, Message onComplete); /** - * Get the voice mail access phone number. Typically dialed when the - * user holds the "1" key in the phone app. May return null if not + * Get the voice mail access phone number. Typically dialed when the + * user holds the "1" key in the phone app. May return null if not * available or the SIM is not ready.

            */ String getVoiceMailNumber(); @@ -684,8 +774,8 @@ public interface Phone { * Returns the alpha tag associated with the voice mail number. * If there is no alpha tag associated or the record is not yet available, * returns a default localized string.

            - * - * Please use this value instead of some other localized string when + * + * Please use this value instead of some other localized string when * showing a name for this number in the UI. For example, call log * entries should show this alpha tag.

            * @@ -708,29 +798,29 @@ public interface Phone { /** * getCallForwardingOptions - * gets a call forwarding option. The return value of - * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo. - * - * @param commandInterfaceCFReason is one of the valid call forwarding - * CF_REASONS, as defined in - * com.android.internal.telephony.gsm.CommandsInterface + * gets a call forwarding option. The return value of + * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo. + * + * @param commandInterfaceCFReason is one of the valid call forwarding + * CF_REASONS, as defined in + * com.android.internal.telephony.CommandsInterface./code> * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CallForwardInfo for details. + * @see com.android.internal.telephony.CallForwardInfo for details. */ void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete); - + /** * setCallForwardingOptions * sets a call forwarding option. - * - * @param commandInterfaceCFReason is one of the valid call forwarding - * CF_REASONS, as defined in - * com.android.internal.telephony.gsm.CommandsInterface - * @param commandInterfaceCFAction is one of the valid call forwarding - * CF_ACTIONS, as defined in - * com.android.internal.telephony.gsm.CommandsInterface - * @param dialingNumber is the target phone number to forward calls to + * + * @param commandInterfaceCFReason is one of the valid call forwarding + * CF_REASONS, as defined in + * com.android.internal.telephony.CommandsInterface./code> + * @param commandInterfaceCFAction is one of the valid call forwarding + * CF_ACTIONS, as defined in + * com.android.internal.telephony.CommandsInterface./code> + * @param dialingNumber is the target phone number to forward calls to * @param timerSeconds is used by CFNRy to indicate the timeout before * forwarding is attempted. * @param onComplete a callback message when the action is completed. @@ -740,83 +830,83 @@ public interface Phone { String dialingNumber, int timerSeconds, Message onComplete); - + /** * getOutgoingCallerIdDisplay - * gets outgoing caller id display. The return value of + * gets outgoing caller id display. The return value of * ((AsyncResult)onComplete.obj) is an array of int, with a length of 2. - * + * * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CommandsInterface.getCLIR for details. + * @see com.android.internal.telephony.CommandsInterface.getCLIR for details. */ void getOutgoingCallerIdDisplay(Message onComplete); - + /** * setOutgoingCallerIdDisplay - * sets a call forwarding option. - * - * @param commandInterfaceCLIRMode is one of the valid call CLIR - * modes, as defined in - * com.android.internal.telephony.gsm.CommandsInterface + * sets a call forwarding option. + * + * @param commandInterfaceCLIRMode is one of the valid call CLIR + * modes, as defined in + * com.android.internal.telephony.CommandsInterface./code> * @param onComplete a callback message when the action is completed. */ void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete); - + /** * getCallWaiting - * gets call waiting activation state. The return value of + * gets call waiting activation state. The return value of * ((AsyncResult)onComplete.obj) is an array of int, with a length of 1. - * + * * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CommandsInterface.queryCallWaiting for details. + * @see com.android.internal.telephony.CommandsInterface.queryCallWaiting for details. */ void getCallWaiting(Message onComplete); - + /** * setCallWaiting - * sets a call forwarding option. - * - * @param enable is a boolean representing the state that you are + * sets a call forwarding option. + * + * @param enable is a boolean representing the state that you are * requesting, true for enabled, false for disabled. * @param onComplete a callback message when the action is completed. */ void setCallWaiting(boolean enable, Message onComplete); - + /** * Scan available networks. This method is asynchronous; . * On completion, response.obj is set to an AsyncResult with * one of the following members:.

            *

              - *
            • response.obj.result will be a List of - * com.android.internal.telephony.gsm.NetworkInfo objects, or
            • - *
            • response.obj.exception will be set with an exception + *
            • response.obj.result will be a List of + * com.android.internal.telephony.gsm.NetworkInfo objects, or
            • + *
            • response.obj.exception will be set with an exception * on failure.
            • *
            */ - void getAvailableNetworks(Message response); + void getAvailableNetworks(Message response); /** * Switches network selection mode to "automatic", re-scanning and * re-selecting a network if appropriate. - * - * @param response The message to dispatch when the network selection + * + * @param response The message to dispatch when the network selection * is complete. - * - * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo, + * + * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo, * android.os.Message ) */ void setNetworkSelectionModeAutomatic(Message response); /** - * Manually selects a network. response is + * Manually selects a network. response is * dispatched when this is complete. response.obj will be * an AsyncResult, and response.obj.exception will be non-null * on failure. - * + * * @see #setNetworkSelectionModeAutomatic(Message) */ - void selectNetworkManually(NetworkInfo network, + void selectNetworkManually(NetworkInfo network, Message response); /** @@ -834,6 +924,21 @@ public interface Phone { */ void getPreferredNetworkType(Message response); + /** + * Gets the default SMSC address. + * + * @param result Callback message contains the SMSC address. + */ + void getSmscAddress(Message result); + + /** + * Sets the default SMSC address. + * + * @param address new SMSC address + * @param result Callback message is empty on completion + */ + void setSmscAddress(String address, Message result); + /** * Query neighboring cell IDs. response is dispatched when * this is complete. response.obj will be an AsyncResult, @@ -843,7 +948,7 @@ public interface Phone { * of available cell IDs. Cell IDs are in hexadecimal format. * * @param response callback message that is dispatched when the query - * completes. + * completes. */ void getNeighboringCids(Message response); @@ -856,28 +961,28 @@ public interface Phone { * AsyncResult. Message.obj.result will be * a Connection object.

            * - * Message.arg1 will be the post dial character being processed, + * Message.arg1 will be the post dial character being processed, * or 0 ('\0') if end of string.

            * - * If Connection.getPostDialState() == WAIT, - * the application must call - * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar() - * Connection.proceedAfterWaitChar()} or - * {@link com.android.internal.telephony.Connection#cancelPostDial() + * If Connection.getPostDialState() == WAIT, + * the application must call + * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar() + * Connection.proceedAfterWaitChar()} or + * {@link com.android.internal.telephony.Connection#cancelPostDial() * Connection.cancelPostDial()} - * for the telephony system to continue playing the post-dial + * for the telephony system to continue playing the post-dial * DTMF sequence.

            * - * If Connection.getPostDialState() == WILD, - * the application must call + * If Connection.getPostDialState() == WILD, + * the application must call * {@link com.android.internal.telephony.Connection#proceedAfterWildChar * Connection.proceedAfterWildChar()} - * or - * {@link com.android.internal.telephony.Connection#cancelPostDial() + * or + * {@link com.android.internal.telephony.Connection#cancelPostDial() * Connection.cancelPostDial()} - * for the telephony system to continue playing the + * for the telephony system to continue playing the * post-dial DTMF sequence.

            - * + * * Only one post dial character handler may be set.

            * Calling this method with "h" equal to null unsets this handler.

            */ @@ -885,19 +990,19 @@ public interface Phone { /** - * Mutes or unmutes the microphone for the active call. The microphone - * is automatically unmuted if a call is answered, dialed, or resumed + * Mutes or unmutes the microphone for the active call. The microphone + * is automatically unmuted if a call is answered, dialed, or resumed * from a holding state. - * - * @param muted true to mute the microphone, + * + * @param muted true to mute the microphone, * false to activate the microphone. */ void setMute(boolean muted); /** - * Gets current mute status. Use - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * Gets current mute status. Use + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()} * as a change notifcation, although presently phone state changed is not * fired when setMute() is called. @@ -908,12 +1013,12 @@ public interface Phone { /** * Invokes RIL_REQUEST_OEM_HOOK_RAW on RIL implementation. - * + * * @param data The data for the request. - * @param response On success, + * @param response On success, * (byte[])(((AsyncResult)response.obj).result) - * On failure, - * (((AsyncResult)response.obj).result) == null and + * On failure, + * (((AsyncResult)response.obj).result) == null and * (((AsyncResult)response.obj).exception) being an instance of * com.android.internal.telephony.gsm.CommandException * @@ -923,13 +1028,13 @@ public interface Phone { /** * Invokes RIL_REQUEST_OEM_HOOK_Strings on RIL implementation. - * + * * @param strings The strings to make available as the request data. - * @param response On success, "response" bytes is + * @param response On success, "response" bytes is * made available as: * (String[])(((AsyncResult)response.obj).result). - * On failure, - * (((AsyncResult)response.obj).result) == null and + * On failure, + * (((AsyncResult)response.obj).result) == null and * (((AsyncResult)response.obj).exception) being an instance of * com.android.internal.telephony.gsm.CommandException * @@ -940,6 +1045,7 @@ public interface Phone { /** * Get the current active PDP context list * + * @deprecated * @param response On success, "response" bytes is * made available as: * (String[])(((AsyncResult)response.obj).result). @@ -950,13 +1056,34 @@ public interface Phone { */ void getPdpContextList(Message response); + /** + * Get the current active Data Call list, substitutes getPdpContextList + * + * @param response On success, "response" bytes is + * made available as: + * (String[])(((AsyncResult)response.obj).result). + * On failure, + * (((AsyncResult)response.obj).result) == null and + * (((AsyncResult)response.obj).exception) being an instance of + * com.android.internal.telephony.gsm.CommandException + */ + void getDataCallList(Message response); + /** * Get current mutiple PDP link status - * + * + * @deprecated * @return list of pdp link connections */ List getCurrentPdpList (); + /** + * Get current mutiple data connection status + * + * @return list of data connections + */ + List getCurrentDataConnectionList (); + /** * Udpate LAC and CID in service state for currnet GSM netowrk registration * @@ -981,11 +1108,11 @@ public interface Phone { void disableLocationUpdates(); /** - * For unit tests; don't send notifications to "Phone" + * For unit tests; don't send notifications to "Phone" * mailbox registrants if true. */ void setUnitTestMode(boolean f); - + /** * @return true If unit test mode is enabled */ @@ -1018,9 +1145,30 @@ public interface Phone { */ void setDataRoamingEnabled(boolean enable); + /** + * Query the CDMA roaming preference setting + * + * @param response is callback message to report one of CDMA_RM_* + */ + void queryCdmaRoamingPreference(Message response); + + /** + * Requests to set the CDMA roaming preference + * @param cdmaRoamingType one of CDMA_RM_* + * @param response is callback message + */ + void setCdmaRoamingPreference(int cdmaRoamingType, Message response); + + /** + * Requests to set the CDMA subscription mode + * @param cdmaSubscriptionType one of CDMA_SUBSCRIPTION_* + * @param response is callback message + */ + void setCdmaSubscription(int cdmaSubscriptionType, Message response); + /** * If this is a simulated phone interface, returns a SimulatedRadioControl. - * @ return A SimulatedRadioControl if this is a simulated interface; + * @ return A SimulatedRadioControl if this is a simulated interface; * otherwise, null. */ SimulatedRadioControl getSimulatedRadioControl(); @@ -1109,7 +1257,7 @@ public interface Phone { public String[] getDnsServers(String apnType); /** - * Retrieves the unique device ID, e.g., IMEI for GSM phones. + * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. */ String getDeviceId(); @@ -1125,7 +1273,81 @@ public interface Phone { String getSubscriberId(); /** - * Retrieves the serial number of the SIM, if applicable. + * Retrieves the serial number of the ICC, if applicable. + */ + String getIccSerialNumber(); + + //***** CDMA support methods + + + /** + * Retrieves the ESN for CDMA phones. + */ + String getEsn(); + + /** + * Retrieves MEID for CDMA phones. + */ + String getMeid(); + + /** + * Retrieves the PhoneSubInfo of the Phone + */ + public PhoneSubInfo getPhoneSubInfo(); + + /** + * Retrieves the IccSmsInterfaceManager of the Phone */ - String getSimSerialNumber(); + public IccSmsInterfaceManager getIccSmsInterfaceManager(); + + /** + * Retrieves the IccPhoneBookInterfaceManager of the Phone + */ + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(); + + /** + * setTTYModeEnabled + * sets a TTY mode option. + * + * @param enable is a boolean representing the state that you are + * requesting, true for enabled, false for disabled. + * @param onComplete a callback message when the action is completed + */ + void setTTYModeEnabled(boolean enable, Message onComplete); + + /** + * queryTTYModeEnabled + * query the status of the TTY mode + * + * @param onComplete a callback message when the action is completed. + */ + void queryTTYModeEnabled(Message onComplete); + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + void activateCellBroadcastSms(int activate, Message response); + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + void getCellBroadcastSmsConfig(Message response); + + /** + * Configure cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response); + + public void notifyDataActivity(); } diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 3571f02dda71e77b7c14505d86fbd6a8b0f744b6..0314034f2424078823d2dda8a35f6eeeea4197b6 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -20,23 +20,30 @@ import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.content.Context; import android.content.res.Configuration; +import android.content.SharedPreferences; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; +import android.os.Message; import android.os.RegistrantList; import android.os.SystemProperties; +import android.preference.PreferenceManager; import android.telephony.ServiceState; +import android.text.TextUtils; import android.util.Log; + import com.android.internal.R; +import com.android.internal.telephony.gsm.PdpConnection; import com.android.internal.telephony.test.SimulatedRadioControl; import java.util.List; import java.util.Locale; + /** - * (Not for SDK use) + * (Not for SDK use) * A base implementation for the com.android.internal.telephony.Phone interface. - * + * * Note that implementations of Phone.java are expected to be used * from a single application thread. This should be the same thread that * originally called PhoneFactory to obtain the interface. @@ -46,42 +53,101 @@ import java.util.Locale; */ public abstract class PhoneBase implements Phone { - private static final String LOG_TAG = "GSM"; + private static final String LOG_TAG = "PHONE"; + private static final boolean LOCAL_DEBUG = true; + + // Key used to read and write the saved network selection value + public static final String NETWORK_SELECTION_KEY = "network_selection_key"; + + // Key used to read/write "disable data connection on boot" pref (used for testing) + public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; + + //***** Event Constants + protected static final int EVENT_RADIO_AVAILABLE = 1; + /** Supplementary Service Notification received. */ + protected static final int EVENT_SSN = 2; + protected static final int EVENT_SIM_RECORDS_LOADED = 3; + protected static final int EVENT_MMI_DONE = 4; + protected static final int EVENT_RADIO_ON = 5; + protected static final int EVENT_GET_BASEBAND_VERSION_DONE = 6; + protected static final int EVENT_USSD = 7; + protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; + protected static final int EVENT_GET_IMEI_DONE = 9; + protected static final int EVENT_GET_IMEISV_DONE = 10; + protected static final int EVENT_GET_SIM_STATUS_DONE = 11; + protected static final int EVENT_SET_CALL_FORWARD_DONE = 12; + protected static final int EVENT_GET_CALL_FORWARD_DONE = 13; + protected static final int EVENT_CALL_RING = 14; + // Used to intercept the carrier selection calls so that + // we can save the values. + protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15; + protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16; + protected static final int EVENT_SET_CLIR_COMPLETE = 17; + protected static final int EVENT_REGISTERED_TO_NETWORK = 18; + protected static final int EVENT_SET_VM_NUMBER_DONE = 19; + // Events for CDMA support + protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 20; + protected static final int EVENT_RUIM_RECORDS_LOADED = 21; + protected static final int EVENT_NV_READY = 22; + protected static final int EVENT_SET_ENHANCED_VP = 23; + + // Key used to read/write current CLIR setting + public static final String CLIR_KEY = "clir_key"; + + // Key used to read/write "disable DNS server check" pref (used for testing) + public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key"; + + //***** Instance Variables + public CommandsInterface mCM; + protected IccFileHandler mIccFileHandler; + boolean mDnsCheckDisabled = false; - protected final RegistrantList mPhoneStateRegistrants + /** + * Set a system property, unless we're in unit test mode + */ + public void + setSystemProperty(String property, String value) { + if(getUnitTestMode()) { + return; + } + SystemProperties.set(property, value); + } + + + protected final RegistrantList mPhoneStateRegistrants = new RegistrantList(); - protected final RegistrantList mNewRingingConnectionRegistrants + protected final RegistrantList mNewRingingConnectionRegistrants = new RegistrantList(); - protected final RegistrantList mIncomingRingRegistrants + protected final RegistrantList mIncomingRingRegistrants = new RegistrantList(); - - protected final RegistrantList mDisconnectRegistrants + + protected final RegistrantList mDisconnectRegistrants = new RegistrantList(); - protected final RegistrantList mServiceStateRegistrants + protected final RegistrantList mServiceStateRegistrants = new RegistrantList(); - - protected final RegistrantList mMmiCompleteRegistrants + + protected final RegistrantList mMmiCompleteRegistrants = new RegistrantList(); - protected final RegistrantList mMmiRegistrants + protected final RegistrantList mMmiRegistrants = new RegistrantList(); - protected final RegistrantList mUnknownConnectionRegistrants + protected final RegistrantList mUnknownConnectionRegistrants = new RegistrantList(); - - protected final RegistrantList mSuppServiceFailedRegistrants + + protected final RegistrantList mSuppServiceFailedRegistrants = new RegistrantList(); - + protected Looper mLooper; /* to insure registrants are in correct thread*/ protected Context mContext; - /** - * PhoneNotifier is an abstraction for all system-wide - * state change notification. DefaultPhoneNotifier is + /** + * PhoneNotifier is an abstraction for all system-wide + * state change notification. DefaultPhoneNotifier is * used here unless running we're inside a unit test. */ protected PhoneNotifier mNotifier; @@ -94,7 +160,7 @@ public abstract class PhoneBase implements Phone { * Constructs a PhoneBase in normal (non-unit test) mode. * * @param context Context object from hosting application - * @param notifier An instance of DefaultPhoneNotifier, + * @param notifier An instance of DefaultPhoneNotifier, * unless unit testing. */ protected PhoneBase(PhoneNotifier notifier, Context context) { @@ -105,13 +171,13 @@ public abstract class PhoneBase implements Phone { * Constructs a PhoneBase in normal (non-unit test) mode. * * @param context Context object from hosting application - * @param notifier An instance of DefaultPhoneNotifier, + * @param notifier An instance of DefaultPhoneNotifier, * unless unit testing. - * @param unitTestMode when true, prevents notifications + * @param unitTestMode when true, prevents notifications * of state change events */ - protected PhoneBase(PhoneNotifier notifier, Context context, - boolean unitTestMode) { + protected PhoneBase(PhoneNotifier notifier, Context context, + boolean unitTestMode) { this.mNotifier = notifier; this.mContext = context; mLooper = Looper.myLooper(); @@ -119,6 +185,9 @@ public abstract class PhoneBase implements Phone { setLocaleByCarrier(); setUnitTestMode(unitTestMode); + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); } // Inherited documentation suffices. @@ -126,6 +195,26 @@ public abstract class PhoneBase implements Phone { return mContext; } + /** + * Disables the DNS check (i.e., allows "0.0.0.0"). + * Useful for lab testing environment. + * @param b true disables the check, false enables. + */ + public void disableDnsCheck(boolean b) { + mDnsCheckDisabled = b; + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b); + editor.commit(); + } + + /** + * Returns true if the DNS check is currently disabled. + */ + public boolean isDnsCheckDisabled() { + return mDnsCheckDisabled; + } + // Inherited documentation suffices. public void registerForPhoneStateChanged(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -137,29 +226,29 @@ public abstract class PhoneBase implements Phone { public void unregisterForPhoneStateChanged(Handler h) { mPhoneStateRegistrants.remove(h); } - + /** * Notify registrants of a PhoneStateChanged. - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyCallStateChangedP() { AsyncResult ar = new AsyncResult(null, this, null); mPhoneStateRegistrants.notifyRegistrants(ar); } - + // Inherited documentation suffices. public void registerForUnknownConnection(Handler h, int what, Object obj) { checkCorrectThread(h); - + mUnknownConnectionRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForUnknownConnection(Handler h) { mUnknownConnectionRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForNewRingingConnection( Handler h, int what, Object obj) { @@ -173,12 +262,33 @@ public abstract class PhoneBase implements Phone { mNewRingingConnectionRegistrants.remove(h); } + // Inherited documentation suffices. + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + mCM.registerForInCallVoicePrivacyOn(h,what,obj); + } + + // Inherited documentation suffices. + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mCM.unregisterForInCallVoicePrivacyOn(h); + } + + // Inherited documentation suffices. + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + mCM.registerForInCallVoicePrivacyOff(h,what,obj); + } + + // Inherited documentation suffices. + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mCM.unregisterForInCallVoicePrivacyOff(h); + } + + /** * Notifiy registrants of a new ringing Connection. - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ - protected void notifyNewRingingConnectionP(Connection cn) { + protected void notifyNewRingingConnectionP(Connection cn) { AsyncResult ar = new AsyncResult(null, cn, null); mNewRingingConnectionRegistrants.notifyRegistrants(ar); } @@ -187,15 +297,15 @@ public abstract class PhoneBase implements Phone { public void registerForIncomingRing( Handler h, int what, Object obj) { checkCorrectThread(h); - + mIncomingRingRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForIncomingRing(Handler h) { mIncomingRingRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForDisconnect(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -211,15 +321,15 @@ public abstract class PhoneBase implements Phone { // Inherited documentation suffices. public void registerForSuppServiceFailed(Handler h, int what, Object obj) { checkCorrectThread(h); - + mSuppServiceFailedRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForSuppServiceFailed(Handler h) { mSuppServiceFailedRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForMmiInitiate(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -231,7 +341,7 @@ public abstract class PhoneBase implements Phone { public void unregisterForMmiInitiate(Handler h) { mMmiRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForMmiComplete(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -247,10 +357,31 @@ public abstract class PhoneBase implements Phone { } /** - * Subclasses should override this. See documentation in superclass. + * Method to retrieve the saved operator id from the Shared Preferences + */ + private String getSavedNetworkSelection() { + // open the shared preferences and search with our key. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + return sp.getString(NETWORK_SELECTION_KEY, ""); + } + + /** + * Method to restore the previously saved operator id, or reset to + * automatic selection, all depending upon the value in the shared + * preferences. */ - public abstract List getPendingMmiCodes(); - + public void restoreSavedNetworkSelection(Message response) { + // retrieve the operator id + String networkSelection = getSavedNetworkSelection(); + + // set to auto if the id is empty, otherwise select the network. + if (TextUtils.isEmpty(networkSelection)) { + mCM.setNetworkSelectionModeAutomatic(response); + } else { + mCM.setNetworkSelectionModeManual(networkSelection, response); + } + } + // Inherited documentation suffices. public void setUnitTestMode(boolean f) { mUnitTestMode = f; @@ -260,11 +391,11 @@ public abstract class PhoneBase implements Phone { public boolean getUnitTestMode() { return mUnitTestMode; } - + /** * To be invoked when a voice call Connection disconnects. * - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyDisconnectP(Connection cn) { @@ -286,7 +417,7 @@ public abstract class PhoneBase implements Phone { } /** - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyServiceStateChangedP(ServiceState ss) { @@ -312,7 +443,7 @@ public abstract class PhoneBase implements Phone { private void checkCorrectThread(Handler h) { if (h.getLooper() != mLooper) { throw new RuntimeException( - "com.android.internal.telephony.Phone must be used from within one thread"); + "com.android.internal.telephony.Phone must be used from within one thread"); } } @@ -359,7 +490,7 @@ public abstract class PhoneBase implements Phone { if (null == language) { return; // no match possible } - language.toLowerCase(); + language = language.toLowerCase(); if (null == country) { country = ""; } @@ -372,13 +503,12 @@ public abstract class PhoneBase implements Phone { final int N = locales.length; String bestMatch = null; for(int i = 0; i < N; i++) { - if (locales[i]!=null && locales[i].length() >= 2 && + // only match full (lang + country) locales + if (locales[i]!=null && locales[i].length() >= 5 && locales[i].substring(0,2).equals(language)) { - if (locales[i].length() >= 5) { - if (locales[i].substring(3,5).equals(country)) { - bestMatch = locales[i]; - break; - } + if (locales[i].substring(3,5).equals(country)) { + bestMatch = locales[i]; + break; } else if (null == bestMatch) { bestMatch = locales[i]; } @@ -387,12 +517,8 @@ public abstract class PhoneBase implements Phone { if (null != bestMatch) { 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.locale = new Locale(bestMatch.substring(0,2), + bestMatch.substring(3,5)); config.userSetLocale = true; am.updateConfiguration(config); } @@ -401,4 +527,115 @@ public abstract class PhoneBase implements Phone { } } } + + /* + * Retrieves the Handler of the Phone instance + */ + public abstract Handler getHandler(); + + /** + * Retrieves the IccFileHandler of the Phone instance + */ + public abstract IccFileHandler getIccFileHandler(); + + + /** + * Query the status of the CDMA roaming preference + */ + public void queryCdmaRoamingPreference(Message response) { + mCM.queryCdmaRoamingPreference(response); + } + + /** + * Set the status of the CDMA roaming preference + */ + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + mCM.setCdmaRoamingPreference(cdmaRoamingType, response); + } + + /** + * Set the status of the CDMA subscription mode + */ + public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { + mCM.setCdmaSubscription(cdmaSubscriptionType, response); + } + + /** + * Set the preferred Network Type: Global, CDMA only or GSM/UMTS only + */ + public void setPreferredNetworkType(int networkType, Message response) { + mCM.setPreferredNetworkType(networkType, response); + } + + /** + * Set the status of the preferred Network Type: Global, CDMA only or GSM/UMTS only + */ + public void getPreferredNetworkType(Message response) { + mCM.getPreferredNetworkType(response); + } + + public void getSmscAddress(Message result) { + mCM.getSmscAddress(result); + } + + public void setSmscAddress(String address, Message result) { + mCM.setSmscAddress(address, result); + } + + public void setTTYModeEnabled(boolean enable, Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void queryTTYModeEnabled(Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + /** + * This should only be called in GSM mode. + * Only here for some backward compatibility + * issues concerning the GSMPhone class. + * @deprecated + */ + public List getCurrentPdpList() { + return null; + } + + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void getEnhancedVoicePrivacy(Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void setBandMode(int bandMode, Message response) { + mCM.setBandMode(bandMode, response); + } + + public void queryAvailableBandMode(Message response) { + mCM.queryAvailableBandMode(response); + } + + public void invokeOemRilRequestRaw(byte[] data, Message response) { + mCM.invokeOemRilRequestRaw(data, response); + } + + public void invokeOemRilRequestStrings(String[] strings, Message response) { + mCM.invokeOemRilRequestStrings(strings, response); + } + + public void notifyDataActivity() { + mNotifier.notifyDataActivity(this); + } + + public void notifyDataConnection(String reason) { + mNotifier.notifyDataConnection(this, reason); + } + + public abstract String getPhoneName(); + } diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java index 0ca5f45c462bf57a48235ad7736fe2b675c34720..86e2f0449da4fc1fb57036c3bae8de4899e94c31 100644 --- a/telephony/java/com/android/internal/telephony/PhoneFactory.java +++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java @@ -16,80 +16,55 @@ package com.android.internal.telephony; -import java.util.ArrayList; -import java.util.List; -import java.io.IOException; -import java.net.InetSocketAddress; - -import java.util.Collections; - -import android.util.Log; -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.gsm.RIL; -import com.android.internal.telephony.test.ModelInterpreter; -import com.android.internal.telephony.test.SimulatedCommands; -import android.os.Looper; -import android.os.SystemProperties; import android.content.Context; -import android.content.Intent; import android.net.LocalServerSocket; -import android.app.ActivityManagerNative; +import android.os.Looper; +import android.provider.Settings; +import android.util.Log; + +import com.android.internal.telephony.cdma.CDMAPhone; +import com.android.internal.telephony.gsm.GSMPhone; /** * {@hide} */ -public class PhoneFactory -{ - static final String LOG_TAG="GSM"; - +public class PhoneFactory { + static final String LOG_TAG = "PHONE"; static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000; static final int SOCKET_OPEN_MAX_RETRY = 3; - //***** Class Variables + //***** Class Variables - static private ArrayList sPhones = new ArrayList(); + static private Phone sProxyPhone = null; + static private CommandsInterface sCommandsInterface = null; static private boolean sMadeDefaults = false; static private PhoneNotifier sPhoneNotifier; static private Looper sLooper; + static private Context sContext; - static private Object testMailbox; - - //***** Class Methods + static final int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE; - private static void - useNewRIL(Context context) - { - ModelInterpreter mi = null; - GSMPhone phone; + static final int preferredCdmaSubscription = RILConstants.PREFERRED_CDMA_SUBSCRIPTION; - try { - if (false) { - mi = new ModelInterpreter(new InetSocketAddress("127.0.0.1", 6502)); - } - - phone = new GSMPhone(context, new RIL(context), sPhoneNotifier); + //***** Class Methods - registerPhone (phone); - } catch (IOException ex) { - Log.e(LOG_TAG, "Error creating ModelInterpreter", ex); - } + public static void makeDefaultPhones(Context context) { + makeDefaultPhone(context); } - /** * FIXME replace this with some other way of making these * instances */ - public static void - makeDefaultPhones(Context context) - { - synchronized(Phone.class) { - if (!sMadeDefaults) { + public static void makeDefaultPhone(Context context) { + synchronized(Phone.class) { + if (!sMadeDefaults) { sLooper = Looper.myLooper(); + sContext = context; if (sLooper == null) { throw new RuntimeException( - "PhoneFactory.makeDefaultPhones must be called from Looper thread"); + "PhoneFactory.makeDefaultPhone must be called from Looper thread"); } int retryCount = 0; @@ -109,7 +84,7 @@ public class PhoneFactory break; } else if (retryCount > SOCKET_OPEN_MAX_RETRY) { throw new RuntimeException("PhoneFactory probably already running"); - }else { + } else { try { Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { @@ -119,44 +94,66 @@ public class PhoneFactory sPhoneNotifier = new DefaultPhoneNotifier(); - if ((SystemProperties.get("ro.radio.noril","")).equals("")) { - useNewRIL(context); - } else { - GSMPhone phone; - phone = new GSMPhone(context, new SimulatedCommands(), sPhoneNotifier); - registerPhone (phone); + //Get preferredNetworkMode from Settings.System + int networkMode = Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); + Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode)); + + //Get preferredNetworkMode from Settings.System + int cdmaSubscription = Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION, preferredCdmaSubscription); + Log.i(LOG_TAG, "Cdma Subscription set to " + Integer.toString(cdmaSubscription)); + + //reads the system properties and makes commandsinterface + sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); + + switch(networkMode) { + case RILConstants.NETWORK_MODE_CDMA: + case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: + case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: + case RILConstants.NETWORK_MODE_GLOBAL: + sProxyPhone = new PhoneProxy(new CDMAPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating CDMAPhone"); + break; + case RILConstants.NETWORK_MODE_WCDMA_PREF: + case RILConstants.NETWORK_MODE_GSM_ONLY: + case RILConstants.NETWORK_MODE_WCDMA_ONLY: + case RILConstants.NETWORK_MODE_GSM_UMTS: + default: + sProxyPhone = new PhoneProxy(new GSMPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating GSMPhone"); + break; } - sMadeDefaults = true; } } } - public static Phone getDefaultPhone() - { - if (!sMadeDefaults) { - throw new IllegalStateException("Default phones haven't been made yet!"); - } - + public static Phone getDefaultPhone() { if (sLooper != Looper.myLooper()) { throw new RuntimeException( "PhoneFactory.getDefaultPhone must be called from Looper thread"); } - synchronized (sPhones) { - return sPhones.isEmpty() ? null : sPhones.get(0); + if (!sMadeDefaults) { + throw new IllegalStateException("Default phones haven't been made yet!"); } + return sProxyPhone; } - - public static void registerPhone(Phone p) - { - if (sLooper != Looper.myLooper()) { - throw new RuntimeException( - "PhoneFactory.getDefaultPhone must be called from Looper thread"); + + public static Phone getCdmaPhone() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier); + return phone; } - synchronized (sPhones) { - sPhones.add(p); + } + + public static Phone getGsmPhone() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier); + return phone; } } } - diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..b76d8015a93a4b32c0a51c5946e4733523891001 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -0,0 +1,683 @@ +/* + * 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.app.ActivityManagerNative; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Handler; +import android.os.Message; +import android.preference.PreferenceManager; +import android.telephony.CellLocation; +import android.telephony.ServiceState; +import android.util.Log; + +import com.android.internal.telephony.cdma.CDMAPhone; +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.gsm.NetworkInfo; +import com.android.internal.telephony.gsm.PdpConnection; +import com.android.internal.telephony.test.SimulatedRadioControl; + +import java.util.List; + +public class PhoneProxy extends Handler implements Phone { + public final static Object lockForRadioTechnologyChange = new Object(); +// private static boolean radioTechnologyChangeGsmToCdma = false; +// private static boolean radioTechnologyChangeCdmaToGsm = false; + + private Phone mActivePhone; + private String mOutgoingPhone; + private CommandsInterface mCommandsInterface; + private IccSmsInterfaceManagerProxy mIccSmsInterfaceManagerProxy; + private IccPhoneBookInterfaceManagerProxy mIccPhoneBookInterfaceManagerProxy; + private PhoneSubInfoProxy mPhoneSubInfoProxy; + + private static final int EVENT_RADIO_TECHNOLOGY_CHANGED = 1; + private static final String LOG_TAG = "PHONE"; + + //***** Class Methods + public PhoneProxy(Phone phone) { + mActivePhone = phone; + mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy( + phone.getIccSmsInterfaceManager()); + mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy( + phone.getIccPhoneBookInterfaceManager()); + mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo()); + mCommandsInterface = ((PhoneBase)mActivePhone).mCM; + mCommandsInterface.registerForRadioTechnologyChanged( + this, EVENT_RADIO_TECHNOLOGY_CHANGED, null); + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case EVENT_RADIO_TECHNOLOGY_CHANGED: + //switch Phone from CDMA to GSM or vice versa + mOutgoingPhone = ((PhoneBase)mActivePhone).getPhoneName(); + logd("Switching phone from " + mOutgoingPhone + "Phone to " + + (mOutgoingPhone.equals("GSM") ? "CDMAPhone" : "GSMPhone") ); + boolean oldPowerState = false; //old power state to off + if (mCommandsInterface.getRadioState().isOn()) { + oldPowerState = true; + logd("Setting Radio Power to Off"); + mCommandsInterface.setRadioPower(false, null); + } + if(mOutgoingPhone.equals("GSM")) { + logd("Make a new CDMAPhone and destroy the old GSMPhone."); + + ((GSMPhone)mActivePhone).dispose(); + Phone oldPhone = mActivePhone; + + //Give the garbage collector a hint to start the garbage collection asap + // NOTE this has been disabled since radio technology change could happen during + // e.g. a multimedia playing and could slow the system. Tests needs to be done + // to see the effects of the GC call here when system is busy. + //System.gc(); + + mActivePhone = PhoneFactory.getCdmaPhone(); + logd("Resetting Radio"); + mCommandsInterface.setRadioPower(oldPowerState, null); + ((GSMPhone)oldPhone).removeReferences(); + oldPhone = null; + } else { + logd("Make a new GSMPhone and destroy the old CDMAPhone."); + + ((CDMAPhone)mActivePhone).dispose(); + //mActivePhone = null; + Phone oldPhone = mActivePhone; + + // Give the GC a hint to start the garbage collection asap + // NOTE this has been disabled since radio technology change could happen during + // e.g. a multimedia playing and could slow the system. Tests needs to be done + // to see the effects of the GC call here when system is busy. + //System.gc(); + + mActivePhone = PhoneFactory.getGsmPhone(); + logd("Resetting Radio:"); + mCommandsInterface.setRadioPower(oldPowerState, null); + ((CDMAPhone)oldPhone).removeReferences(); + oldPhone = null; + } + + //Set the new interfaces in the proxy's + mIccSmsInterfaceManagerProxy.setmIccSmsInterfaceManager( + mActivePhone.getIccSmsInterfaceManager()); + mIccPhoneBookInterfaceManagerProxy.setmIccPhoneBookInterfaceManager( + mActivePhone.getIccPhoneBookInterfaceManager()); + mPhoneSubInfoProxy.setmPhoneSubInfo(this.mActivePhone.getPhoneSubInfo()); + mCommandsInterface = ((PhoneBase)mActivePhone).mCM; + + //Send an Intent to the PhoneApp that we had a radio technology change + Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); + intent.putExtra(Phone.PHONE_NAME_KEY, mActivePhone.getPhoneName()); + ActivityManagerNative.broadcastStickyIntent(intent, null); + + break; + default: + Log.e(LOG_TAG, "Error! This handler was not registered for this message type. Message: " + + msg.what); + break; + } + super.handleMessage(msg); + } + + private void logv(String msg) { + Log.v(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logd(String msg) { + Log.d(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logw(String msg) { + Log.w(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void loge(String msg) { + Log.e(LOG_TAG, "[PhoneProxy] " + msg); + } + + + public ServiceState getServiceState() { + return mActivePhone.getServiceState(); + } + + public CellLocation getCellLocation() { + return mActivePhone.getCellLocation(); + } + + public DataState getDataConnectionState() { + return mActivePhone.getDataConnectionState(); + } + + public DataActivityState getDataActivityState() { + return mActivePhone.getDataActivityState(); + } + + public Context getContext() { + return mActivePhone.getContext(); + } + + public void disableDnsCheck(boolean b) { + mActivePhone.disableDnsCheck(b); + } + + public boolean isDnsCheckDisabled() { + return mActivePhone.isDnsCheckDisabled(); + } + + public State getState() { + return mActivePhone.getState(); + } + + public String getPhoneName() { + return mActivePhone.getPhoneName(); + } + + public String[] getActiveApnTypes() { + return mActivePhone.getActiveApnTypes(); + } + + public String getActiveApn() { + return mActivePhone.getActiveApn(); + } + + public int getSignalStrengthASU() { + return mActivePhone.getSignalStrengthASU(); + } + + public void registerForUnknownConnection(Handler h, int what, Object obj) { + mActivePhone.registerForUnknownConnection(h, what, obj); + } + + public void unregisterForUnknownConnection(Handler h) { + mActivePhone.unregisterForUnknownConnection(h); + } + + public void registerForPhoneStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForPhoneStateChanged(h, what, obj); + } + + public void unregisterForPhoneStateChanged(Handler h) { + mActivePhone.unregisterForPhoneStateChanged(h); + } + + public void registerForNewRingingConnection(Handler h, int what, Object obj) { + mActivePhone.registerForNewRingingConnection(h, what, obj); + } + + public void unregisterForNewRingingConnection(Handler h) { + mActivePhone.unregisterForNewRingingConnection(h); + } + + public void registerForIncomingRing(Handler h, int what, Object obj) { + mActivePhone.registerForIncomingRing(h, what, obj); + } + + public void unregisterForIncomingRing(Handler h) { + mActivePhone.unregisterForIncomingRing(h); + } + + public void registerForDisconnect(Handler h, int what, Object obj) { + mActivePhone.registerForDisconnect(h, what, obj); + } + + public void unregisterForDisconnect(Handler h) { + mActivePhone.unregisterForDisconnect(h); + } + + public void registerForMmiInitiate(Handler h, int what, Object obj) { + mActivePhone.registerForMmiInitiate(h, what, obj); + } + + public void unregisterForMmiInitiate(Handler h) { + mActivePhone.unregisterForMmiInitiate(h); + } + + public void registerForMmiComplete(Handler h, int what, Object obj) { + mActivePhone.registerForMmiComplete(h, what, obj); + } + + public void unregisterForMmiComplete(Handler h) { + mActivePhone.unregisterForMmiComplete(h); + } + + public List getPendingMmiCodes() { + return mActivePhone.getPendingMmiCodes(); + } + + public void sendUssdResponse(String ussdMessge) { + mActivePhone.sendUssdResponse(ussdMessge); + } + + public void registerForServiceStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForServiceStateChanged(h, what, obj); + } + + public void unregisterForServiceStateChanged(Handler h) { + mActivePhone.unregisterForServiceStateChanged(h); + } + + public void registerForSuppServiceNotification(Handler h, int what, Object obj) { + mActivePhone.registerForSuppServiceNotification(h, what, obj); + } + + public void unregisterForSuppServiceNotification(Handler h) { + mActivePhone.unregisterForSuppServiceNotification(h); + } + + public void registerForSuppServiceFailed(Handler h, int what, Object obj) { + mActivePhone.registerForSuppServiceFailed(h, what, obj); + } + + public void unregisterForSuppServiceFailed(Handler h) { + mActivePhone.unregisterForSuppServiceFailed(h); + } + + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOn(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOn(h); + } + + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOff(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOff(h); + } + + public boolean getIccRecordsLoaded() { + return mActivePhone.getIccRecordsLoaded(); + } + + public IccCard getIccCard() { + return mActivePhone.getIccCard(); + } + + public void acceptCall() throws CallStateException { + mActivePhone.acceptCall(); + } + + public void rejectCall() throws CallStateException { + mActivePhone.rejectCall(); + } + + public void switchHoldingAndActive() throws CallStateException { + mActivePhone.switchHoldingAndActive(); + } + + public boolean canConference() { + return mActivePhone.canConference(); + } + + public void conference() throws CallStateException { + mActivePhone.conference(); + } + + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + mActivePhone.enableEnhancedVoicePrivacy(enable, onComplete); + } + + public void getEnhancedVoicePrivacy(Message onComplete) { + mActivePhone.getEnhancedVoicePrivacy(onComplete); + } + + public boolean canTransfer() { + return mActivePhone.canTransfer(); + } + + public void explicitCallTransfer() throws CallStateException { + mActivePhone.explicitCallTransfer(); + } + + public void clearDisconnected() { + mActivePhone.clearDisconnected(); + } + + public Call getForegroundCall() { + return mActivePhone.getForegroundCall(); + } + + public Call getBackgroundCall() { + return mActivePhone.getBackgroundCall(); + } + + public Call getRingingCall() { + return mActivePhone.getRingingCall(); + } + + public Connection dial(String dialString) throws CallStateException { + return mActivePhone.dial(dialString); + } + + public boolean handlePinMmi(String dialString) { + return mActivePhone.handlePinMmi(dialString); + } + + public boolean handleInCallMmiCommands(String command) throws CallStateException { + return mActivePhone.handleInCallMmiCommands(command); + } + + public void sendDtmf(char c) { + mActivePhone.sendDtmf(c); + } + + public void startDtmf(char c) { + mActivePhone.startDtmf(c); + } + + public void stopDtmf() { + mActivePhone.stopDtmf(); + } + + public void setRadioPower(boolean power) { + mActivePhone.setRadioPower(power); + } + + public boolean getMessageWaitingIndicator() { + return mActivePhone.getMessageWaitingIndicator(); + } + + public boolean getCallForwardingIndicator() { + return mActivePhone.getCallForwardingIndicator(); + } + + public String getLine1Number() { + return mActivePhone.getLine1Number(); + } + + public String getLine1AlphaTag() { + return mActivePhone.getLine1AlphaTag(); + } + + public void setLine1Number(String alphaTag, String number, Message onComplete) { + mActivePhone.setLine1Number(alphaTag, number, onComplete); + } + + public String getVoiceMailNumber() { + return mActivePhone.getVoiceMailNumber(); + } + + public String getVoiceMailAlphaTag() { + return mActivePhone.getVoiceMailAlphaTag(); + } + + public void setVoiceMailNumber(String alphaTag,String voiceMailNumber, + Message onComplete) { + mActivePhone.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); + } + + public void getCallForwardingOption(int commandInterfaceCFReason, + Message onComplete) { + mActivePhone.getCallForwardingOption(commandInterfaceCFReason, + onComplete); + } + + public void setCallForwardingOption(int commandInterfaceCFReason, + int commandInterfaceCFAction, String dialingNumber, + int timerSeconds, Message onComplete) { + mActivePhone.setCallForwardingOption(commandInterfaceCFReason, + commandInterfaceCFAction, dialingNumber, timerSeconds, onComplete); + } + + public void getOutgoingCallerIdDisplay(Message onComplete) { + mActivePhone.getOutgoingCallerIdDisplay(onComplete); + } + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + Message onComplete) { + mActivePhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, + onComplete); + } + + public void getCallWaiting(Message onComplete) { + mActivePhone.getCallWaiting(onComplete); + } + + public void setCallWaiting(boolean enable, Message onComplete) { + mActivePhone.setCallWaiting(enable, onComplete); + } + + public void getAvailableNetworks(Message response) { + mActivePhone.getAvailableNetworks(response); + } + + public void setNetworkSelectionModeAutomatic(Message response) { + mActivePhone.setNetworkSelectionModeAutomatic(response); + } + + public void selectNetworkManually(NetworkInfo network, Message response) { + mActivePhone.selectNetworkManually(network, response); + } + + public void setPreferredNetworkType(int networkType, Message response) { + mActivePhone.setPreferredNetworkType(networkType, response); + } + + public void getPreferredNetworkType(Message response) { + mActivePhone.getPreferredNetworkType(response); + } + + public void getNeighboringCids(Message response) { + mActivePhone.getNeighboringCids(response); + } + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { + mActivePhone.setOnPostDialCharacter(h, what, obj); + } + + public void setMute(boolean muted) { + mActivePhone.setMute(muted); + } + + public boolean getMute() { + return mActivePhone.getMute(); + } + + public void invokeOemRilRequestRaw(byte[] data, Message response) { + mActivePhone.invokeOemRilRequestRaw(data, response); + } + + public void invokeOemRilRequestStrings(String[] strings, Message response) { + mActivePhone.invokeOemRilRequestStrings(strings, response); + } + + /** + * @deprecated + */ + public void getPdpContextList(Message response) { + mActivePhone.getPdpContextList(response); + } + + public void getDataCallList(Message response) { + mActivePhone.getDataCallList(response); + } + + /** + * @deprecated + */ + public List getCurrentPdpList() { + return mActivePhone.getCurrentPdpList(); + } + + public List getCurrentDataConnectionList() { + return mActivePhone.getCurrentDataConnectionList(); + } + + public void updateServiceLocation(Message response) { + mActivePhone.updateServiceLocation(response); + } + + public void enableLocationUpdates() { + mActivePhone.enableLocationUpdates(); + } + + public void disableLocationUpdates() { + mActivePhone.disableLocationUpdates(); + } + + public void setUnitTestMode(boolean f) { + mActivePhone.setUnitTestMode(f); + } + + public boolean getUnitTestMode() { + return mActivePhone.getUnitTestMode(); + } + + public void setBandMode(int bandMode, Message response) { + mActivePhone.setBandMode(bandMode, response); + } + + public void queryAvailableBandMode(Message response) { + mActivePhone.queryAvailableBandMode(response); + } + + public boolean getDataRoamingEnabled() { + return mActivePhone.getDataRoamingEnabled(); + } + + public void setDataRoamingEnabled(boolean enable) { + mActivePhone.setDataRoamingEnabled(enable); + } + + public void queryCdmaRoamingPreference(Message response) { + mActivePhone.queryCdmaRoamingPreference(response); + } + + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + mActivePhone.setCdmaRoamingPreference(cdmaRoamingType, response); + } + + public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { + mActivePhone.setCdmaSubscription(cdmaSubscriptionType, response); + } + + public SimulatedRadioControl getSimulatedRadioControl() { + return mActivePhone.getSimulatedRadioControl(); + } + + public boolean enableDataConnectivity() { + return mActivePhone.enableDataConnectivity(); + } + + public boolean disableDataConnectivity() { + return mActivePhone.disableDataConnectivity(); + } + + public int enableApnType(String type) { + return mActivePhone.enableApnType(type); + } + + public int disableApnType(String type) { + return mActivePhone.disableApnType(type); + } + + public boolean isDataConnectivityPossible() { + return mActivePhone.isDataConnectivityPossible(); + } + + public String getInterfaceName(String apnType) { + return mActivePhone.getInterfaceName(apnType); + } + + public String getIpAddress(String apnType) { + return mActivePhone.getIpAddress(apnType); + } + + public String getGateway(String apnType) { + return mActivePhone.getGateway(apnType); + } + + public String[] getDnsServers(String apnType) { + return mActivePhone.getDnsServers(apnType); + } + + public String getDeviceId() { + return mActivePhone.getDeviceId(); + } + + public String getDeviceSvn() { + return mActivePhone.getDeviceSvn(); + } + + public String getSubscriberId() { + return mActivePhone.getSubscriberId(); + } + + public String getIccSerialNumber() { + return mActivePhone.getIccSerialNumber(); + } + + public String getEsn() { + return mActivePhone.getEsn(); + } + + public String getMeid() { + return mActivePhone.getMeid(); + } + + public PhoneSubInfo getPhoneSubInfo(){ + return mActivePhone.getPhoneSubInfo(); + } + + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return mActivePhone.getIccSmsInterfaceManager(); + } + + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ + return mActivePhone.getIccPhoneBookInterfaceManager(); + } + + public void setTTYModeEnabled(boolean enable, Message onComplete) { + mActivePhone.setTTYModeEnabled(enable, onComplete); + } + + public void queryTTYModeEnabled(Message onComplete) { + mActivePhone.queryTTYModeEnabled(onComplete); + } + + public void activateCellBroadcastSms(int activate, Message response) { + mActivePhone.activateCellBroadcastSms(activate, response); + } + + public void getCellBroadcastSmsConfig(Message response) { + mActivePhone.getCellBroadcastSmsConfig(response); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { + mActivePhone.setCellBroadcastSmsConfig(configValuesArray, response); + } + + public void notifyDataActivity() { + mActivePhone.notifyDataActivity(); + } + + public void getSmscAddress(Message result) { + mActivePhone.getSmscAddress(result); + } + + public void setSmscAddress(String address, Message result) { + mActivePhone.setSmscAddress(address, result); + } +} + diff --git a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java index 61d4c9fe52715d0c7cd3c6b1d6ef7e2ba120b5ec..fd822cda07bc94b89e43be4d6cca7bad3fe1a24e 100644 --- a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java +++ b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java @@ -32,11 +32,11 @@ import android.util.Log; * * Use android.telephony.TelephonyManager and PhoneStateListener instead. * - * + * */ @Deprecated public final class PhoneStateIntentReceiver extends BroadcastReceiver { - private static final String LOG_TAG = "PhoneStateIntRecv"; + private static final String LOG_TAG = "PHONE"; private static final boolean DBG = false; public static final String INTENT_KEY_ASU = "asu"; @@ -182,7 +182,7 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { if (TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED.equals(action)) { mAsu = intent.getIntExtra(INTENT_KEY_ASU, mAsu); if (DBG) Log.d(LOG_TAG, "onReceiveIntent: set asu=" + mAsu); - + if (mTarget != null && getNotifySignalStrength()) { Message message = Message.obtain(mTarget, mAsuEventWhat); mTarget.sendMessage(message); diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java index 644d1f4f510a98f1ab2a6708356782217c4f0c74..4d1f7e5f1331727d05094cab9cb56c76dec0a580 100644 --- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java @@ -1,10 +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 com.android.internal.telephony; import android.content.Context; -import android.os.ServiceManager; -import com.android.internal.telephony.*; +import android.util.Log; public class PhoneSubInfo extends IPhoneSubInfo.Stub { + static final String LOG_TAG = "PHONE"; private Phone mPhone; private Context mContext; private static final String READ_PHONE_STATE = @@ -13,10 +28,17 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub { public PhoneSubInfo(Phone phone) { mPhone = phone; mContext = phone.getContext(); - ServiceManager.addService("iphonesubinfo", this); } + + public void dispose() { + } + + protected void finalize() { + Log.d(LOG_TAG, "PhoneSubInfo finalized"); + } + /** - * Retrieves the unique device ID, e.g., IMEI for GSM phones. + * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. */ public String getDeviceId() { mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE"); @@ -41,11 +63,11 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub { } /** - * Retrieves the serial number of the SIM, if applicable. + * Retrieves the serial number of the ICC, if applicable. */ - public String getSimSerialNumber() { + public String getIccSerialNumber() { mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE"); - return mPhone.getSimSerialNumber(); + return mPhone.getIccSerialNumber(); } /** diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..450b3a70d88b5d9f68d2e8d002f80d9c2e70b32e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java @@ -0,0 +1,85 @@ +/* + * 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.os.ServiceManager; + + +public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub { + private PhoneSubInfo mPhoneSubInfo; + + public PhoneSubInfoProxy(PhoneSubInfo phoneSubInfo) { + mPhoneSubInfo = phoneSubInfo; + if(ServiceManager.getService("iphonesubinfo") == null) { + ServiceManager.addService("iphonesubinfo", this); + } + } + + public void setmPhoneSubInfo(PhoneSubInfo phoneSubInfo) { + this.mPhoneSubInfo = phoneSubInfo; + } + + public String getDeviceId() { + return mPhoneSubInfo.getDeviceId(); + } + + public String getDeviceSvn() { + return mPhoneSubInfo.getDeviceSvn(); + } + + /** + * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones. + */ + public String getSubscriberId() { + return mPhoneSubInfo.getSubscriberId(); + } + + /** + * Retrieves the serial number of the ICC, if applicable. + */ + public String getIccSerialNumber() { + return mPhoneSubInfo.getIccSerialNumber(); + } + + /** + * Retrieves the phone number string for line 1. + */ + public String getLine1Number() { + return mPhoneSubInfo.getLine1Number(); + } + + /** + * Retrieves the alpha identifier for line 1. + */ + public String getLine1AlphaTag() { + return mPhoneSubInfo.getLine1AlphaTag(); + } + + /** + * Retrieves the voice mail number. + */ + public String getVoiceMailNumber() { + return mPhoneSubInfo.getVoiceMailNumber(); + } + + /** + * Retrieves the alpha identifier associated with the voice mail number. + */ + public String getVoiceMailAlphaTag() { + return mPhoneSubInfo.getVoiceMailAlphaTag(); + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java similarity index 66% rename from telephony/java/com/android/internal/telephony/gsm/RIL.java rename to telephony/java/com/android/internal/telephony/RIL.java index e2d0f7298261b442eea4740c5e14a156ebbcf38c..be18a3993b19b303b0ef17174ed57dba65a1d4fa 100644 --- a/telephony/java/com/android/internal/telephony/gsm/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import static com.android.internal.telephony.gsm.RILConstants.*; +import static com.android.internal.telephony.RILConstants.*; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -31,13 +31,19 @@ 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.telephony.NeighboringCellInfo; +import android.telephony.PhoneNumberUtils; +import android.telephony.SmsManager; +import android.telephony.SmsMessage; import android.util.Config; import android.util.Log; +import com.android.internal.telephony.gsm.NetworkInfo; +import com.android.internal.telephony.gsm.PDPContextState; +import com.android.internal.telephony.gsm.SuppServiceNotification; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -46,8 +52,7 @@ import java.util.Collections; /** * {@hide} */ -class RILRequest -{ +class RILRequest { static final String LOG_TAG = "RILJ"; //***** Class Variables @@ -67,14 +72,14 @@ class RILRequest /** * Retrieves a new RILRequest instance from the pool. - * + * * @param request RIL_REQUEST_* * @param result sent when operation completes * @return a RILRequest instance from the pool. */ static RILRequest obtain(int request, Message result) { RILRequest rr = null; - + synchronized(sPoolSync) { if (sPool != null) { rr = sPool; @@ -83,7 +88,7 @@ class RILRequest sPoolSize--; } } - + if (rr == null) { rr = new RILRequest(); } @@ -108,7 +113,7 @@ class RILRequest /** * Returns a RILRequest instance to the pool. - * + * * Note: This should only be called once per use. */ void release() { @@ -121,21 +126,18 @@ class RILRequest } } - private RILRequest() - { + private RILRequest() { } static void - resetSerial() - { + resetSerial() { synchronized(sSerialMonitor) { sNextSerial = 0; } } String - serialString() - { + serialString() { //Cheesy way to do %04d StringBuilder sb = new StringBuilder(8); String sn; @@ -154,14 +156,13 @@ class RILRequest } void - onError(int error) - { + onError(int error) { CommandException ex; ex = CommandException.fromRilErrno(error); if (RIL.RILJ_LOGD) Log.d(LOG_TAG, serialString() + "< " - + RIL.requestToString(mRequest) + + RIL.requestToString(mRequest) + " error: " + ex); if (mResult != null) { @@ -180,11 +181,10 @@ class RILRequest /** * RIL implementation of the CommandsInterface. * FIXME public only for testing - * + * * {@hide} */ -public final class RIL extends BaseCommands implements CommandsInterface -{ +public final class RIL extends BaseCommands implements CommandsInterface { static final String LOG_TAG = "RILJ"; private static final boolean DBG = false; static final boolean RILJ_LOGD = Config.LOGD; @@ -194,20 +194,20 @@ public final class RIL extends BaseCommands implements CommandsInterface //***** Instance Variables LocalSocket mSocket; - HandlerThread mSenderThread; + HandlerThread mSenderThread; RILSender mSender; Thread mReceiverThread; RILReceiver mReceiver; private Context mContext; WakeLock mWakeLock; int mRequestMessagesPending; - + // Is this the first radio state change? private boolean mInitialRadioStateChange = true; //I'd rather this be LinkedList or something ArrayList mRequestsList = new ArrayList(); - + Object mLastNITZTimeInfo; //***** Events @@ -226,6 +226,11 @@ public final class RIL extends BaseCommands implements CommandsInterface static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000; + // The number of the required config values for broadcast SMS stored in the C struct + // RIL_CDMA_BroadcastServiceInfo + private static final int CDMA_BSI_NO_OF_INTS_STRUCT = 3; + + private static final int CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES = 31; BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { @@ -238,20 +243,18 @@ public final class RIL extends BaseCommands implements CommandsInterface } } }; - - class RILSender extends Handler implements Runnable - { + + class RILSender extends Handler implements Runnable { public RILSender(Looper looper) { super(looper); } - + // Only allocated once byte[] dataLength = new byte[4]; //***** Runnable implementation public void - run() - { + run() { //setup if needed } @@ -259,11 +262,10 @@ public final class RIL extends BaseCommands implements CommandsInterface //***** Handler implemementation public void - handleMessage(Message msg) - { + handleMessage(Message msg) { RILRequest rr = (RILRequest)(msg.obj); RILRequest req = null; - + switch (msg.what) { case EVENT_SEND: /** @@ -300,7 +302,7 @@ public final class RIL extends BaseCommands implements CommandsInterface if (data.length > RIL_MAX_COMMAND_BYTES) { throw new RuntimeException( - "Parcel larger than max bytes allowed! " + "Parcel larger than max bytes allowed! " + data.length); } @@ -311,7 +313,7 @@ public final class RIL extends BaseCommands implements CommandsInterface //Log.v(LOG_TAG, "writing packet: " + data.length + " bytes"); - s.getOutputStream().write(dataLength); + s.getOutputStream().write(dataLength); s.getOutputStream().write(data); } catch (IOException ex) { Log.e(LOG_TAG, "IOException", ex); @@ -351,12 +353,12 @@ public final class RIL extends BaseCommands implements CommandsInterface Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " + " mReqPending=" + mRequestMessagesPending + " mRequestList=" + count); - + for (int i = 0; i < count; i++) { rr = mRequestsList.get(i); Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " + requestToString(rr.mRequest)); - + } } } @@ -383,8 +385,7 @@ public final class RIL extends BaseCommands implements CommandsInterface * @throws IOException */ private static int readRilMessage(InputStream is, byte[] buffer) - throws IOException - { + throws IOException { int countRead; int offset; int remaining; @@ -429,20 +430,17 @@ public final class RIL extends BaseCommands implements CommandsInterface return messageLength; } - class RILReceiver implements Runnable - { + class RILReceiver implements Runnable { byte[] buffer; - RILReceiver() - { + RILReceiver() { buffer = new byte[RIL_MAX_COMMAND_BYTES]; } public void - run() - { + run() { int retryCount = 0; - + try {for (;;) { LocalSocket s = null; LocalSocketAddress l; @@ -460,23 +458,23 @@ public final class RIL extends BaseCommands implements CommandsInterface } catch (IOException ex2) { //ignore failure to close after failure to connect } - + // don't print an error message after the the first time // or after the 8th time if (retryCount == 8) { - Log.e (LOG_TAG, + Log.e (LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL + "' socket after " + retryCount + " times, continuing to retry silently"); } else if (retryCount > 0 && retryCount < 8) { - Log.i (LOG_TAG, + Log.i (LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL + "' socket; retrying after timeout"); } try { - Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); + Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { } @@ -492,7 +490,7 @@ public final class RIL extends BaseCommands implements CommandsInterface int length = 0; try { InputStream is = mSocket.getInputStream(); - + for (;;) { Parcel p; @@ -516,7 +514,7 @@ 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 + + Log.e(LOG_TAG, "Uncaught exception read length=" + length + "Exception:" + tr.toString()); } @@ -524,9 +522,9 @@ public final class RIL extends BaseCommands implements CommandsInterface + "' socket"); setRadioState (RadioState.RADIO_UNAVAILABLE); - + try { - mSocket.close(); + mSocket.close(); } catch (IOException ex) { } @@ -551,15 +549,35 @@ public final class RIL extends BaseCommands implements CommandsInterface - //***** Constructor - + //***** Constructors public - RIL(Context context) - { + RIL(Context context) { + this(context, RILConstants.PREFERRED_NETWORK_MODE, + RILConstants.PREFERRED_CDMA_SUBSCRIPTION); + } + + public RIL(Context context, int networkMode, int cdmaSubscription) { super(context); + mCdmaSubscription = cdmaSubscription; + mNetworkMode = networkMode; + //At startup mPhoneType is first set from networkMode + switch(networkMode) { + case RILConstants.NETWORK_MODE_CDMA: + case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: + case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: + case RILConstants.NETWORK_MODE_GLOBAL: + mPhoneType = RILConstants.CDMA_PHONE; + break; + case RILConstants.NETWORK_MODE_WCDMA_PREF: + case RILConstants.NETWORK_MODE_GSM_ONLY: + case RILConstants.NETWORK_MODE_WCDMA_ONLY: + case RILConstants.NETWORK_MODE_GSM_UMTS: + default: + mPhoneType = RILConstants.GSM_PHONE; + } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); mWakeLock.setReferenceCounted(false); mRequestMessagesPending = 0; @@ -567,10 +585,10 @@ public final class RIL extends BaseCommands implements CommandsInterface mSenderThread = new HandlerThread("RILSender"); mSenderThread.start(); - + Looper looper = mSenderThread.getLooper(); mSender = new RILSender(looper); - + mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, "RILReceiver"); mReceiverThread.start(); @@ -583,9 +601,8 @@ public final class RIL extends BaseCommands implements CommandsInterface //***** CommandsInterface implementation - @Override public void - setOnNITZTime(Handler h, int what, Object obj) - { + @Override public void + setOnNITZTime(Handler h, int what, Object obj) { super.setOnNITZTime(h, what, obj); // Send the last NITZ time if we have it @@ -597,9 +614,10 @@ public final class RIL extends BaseCommands implements CommandsInterface } } - public void - getSimStatus(Message result) - { + public void + getIccStatus(Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -607,9 +625,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPin(String pin, Message result) - { + public void + supplyIccPin(String pin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -620,9 +639,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPuk(String puk, String newPin, Message result) - { + public void + supplyIccPuk(String puk, String newPin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -634,9 +654,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPin2(String pin, Message result) - { + public void + supplyIccPin2(String pin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -647,9 +668,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplySimPuk2(String puk, String newPin2, Message result) - { + public void + supplyIccPuk2(String puk, String newPin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -662,8 +684,9 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - changeSimPin(String oldPin, String newPin, Message result) - { + changeIccPin(String oldPin, String newPin, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -676,8 +699,9 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - changeSimPin2(String oldPin2, String newPin2, Message result) - { + changeIccPin2(String oldPin2, String newPin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -690,8 +714,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) - { + changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -704,9 +727,8 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - supplyNetworkDepersonalization(String netpin, Message result) - { + public void + supplyNetworkDepersonalization(String netpin, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -716,10 +738,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - - public void - getCurrentCalls (Message result) - { + + public void + getCurrentCalls (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -727,19 +748,22 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getPDPContextList(Message result) - { - RILRequest rr = RILRequest.obtain(RIL_REQUEST_PDP_CONTEXT_LIST, result); + public void + getPDPContextList(Message result) { + getDataCallList(result); + } + + public void + getDataCallList(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DATA_CALL_LIST, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } - public void - dial (String address, int clirMode, Message result) - { + public void + dial (String address, int clirMode, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); rr.mp.writeString(address); @@ -750,19 +774,20 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getIMSI(Message result) - { + public void + getIMSI(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result); - if (RILJ_LOGD) 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); } public void - getIMEI(Message result) - { + getIMEI(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEI, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -771,8 +796,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getIMEISV(Message result) - { + getIMEISV(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEISV, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -781,14 +805,14 @@ public final class RIL extends BaseCommands implements CommandsInterface } - public void - hangupConnection (int gsmIndex, Message result) - { + public void + hangupConnection (int gsmIndex, Message result) { if (RILJ_LOGD) riljLog("hangupConnection: gsmIndex=" + gsmIndex); RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP, result); - if (RILJ_LOGD) 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); @@ -796,10 +820,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - hangupWaitingOrBackground (Message result) - { - RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, + public void + hangupWaitingOrBackground (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -808,11 +831,10 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - hangupForegroundResumeBackground (Message result) - { - RILRequest rr + hangupForegroundResumeBackground (Message result) { + RILRequest rr = RILRequest.obtain( - RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, + RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -820,11 +842,10 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - switchWaitingOrHoldingAndActive (Message result) - { - RILRequest rr + switchWaitingOrHoldingAndActive (Message result) { + RILRequest rr = RILRequest.obtain( - RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, + RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -832,9 +853,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - conference (Message result) - { - RILRequest rr + conference (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -843,10 +863,25 @@ public final class RIL extends BaseCommands implements CommandsInterface } + public void setPreferredVoicePrivacy(boolean enable, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, + result); + + rr.mp.writeInt(1); + rr.mp.writeInt(enable ? 1:0); + + send(rr); + } + + public void getPreferredVoicePrivacy(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, + result); + send(rr); + } + public void - separateConnection (int gsmIndex, Message result) - { - RILRequest rr + separateConnection (int gsmIndex, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEPARATE_CONNECTION, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -859,9 +894,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - acceptCall (Message result) - { - RILRequest rr + acceptCall (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ANSWER, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -869,10 +903,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - rejectCall (Message result) - { - RILRequest rr + public void + rejectCall (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_UDUB, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -881,8 +914,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - explicitCallTransfer (Message result) - { + explicitCallTransfer (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, result); @@ -892,9 +924,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getLastCallFailCause (Message result) - { - RILRequest rr + getLastCallFailCause (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -902,11 +933,21 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getLastPdpFailCause (Message result) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_LAST_PDP_FAIL_CAUSE, result); + /** + * @deprecated + */ + public void + getLastPdpFailCause (Message result) { + getLastDataCallFailCause (result); + } + + /** + * The preferred new alternative to getLastPdpFailCause + */ + public void + getLastDataCallFailCause (Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -914,9 +955,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - setMute (boolean enableMute, Message response) - { - RILRequest rr + setMute (boolean enableMute, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_MUTE, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -929,9 +969,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getMute (Message response) - { - RILRequest rr + getMute (Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_MUTE, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -940,9 +979,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - getSignalStrength (Message result) - { - RILRequest rr + getSignalStrength (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIGNAL_STRENGTH, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -950,10 +988,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getRegistrationState (Message result) - { - RILRequest rr + public void + getRegistrationState (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_REGISTRATION_STATE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -961,10 +998,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getGPRSRegistrationState (Message result) - { - RILRequest rr + public void + getGPRSRegistrationState (Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GPRS_REGISTRATION_STATE, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -972,10 +1008,9 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - getOperator(Message result) - { - RILRequest rr + public void + getOperator(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OPERATOR, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -983,14 +1018,13 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void - sendDtmf(char c, Message result) - { - RILRequest rr + public void + sendDtmf(char c, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DTMF, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + rr.mp.writeString(Character.toString(c)); send(rr); @@ -1020,9 +1054,8 @@ public final class RIL extends BaseCommands implements CommandsInterface public void - sendSMS (String smscPDU, String pdu, Message result) - { - RILRequest rr + sendSMS (String smscPDU, String pdu, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result); rr.mp.writeInt(2); @@ -1030,19 +1063,82 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + + send(rr); + } + + public void + sendCdmaSms(byte[] pdu, Message result) { + int address_nbr_of_digits; + int subaddr_nbr_of_digits; + int bearerDataLength; + ByteArrayInputStream bais = new ByteArrayInputStream(pdu); + DataInputStream dis = new DataInputStream(bais); + + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_CDMA_SEND_SMS, result); + + try { + rr.mp.writeInt(dis.readInt()); //teleServiceId + rr.mp.writeByte((byte) dis.readInt()); //servicePresent + rr.mp.writeInt(dis.readInt()); //serviceCategory + rr.mp.writeInt(dis.read()); //address_digit_mode + rr.mp.writeInt(dis.read()); //address_nbr_mode + rr.mp.writeInt(dis.read()); //address_ton + rr.mp.writeInt(dis.read()); //address_nbr_plan + address_nbr_of_digits = (byte) dis.read(); + rr.mp.writeByte((byte) address_nbr_of_digits); + for(int i=0; i < address_nbr_of_digits; i++){ + rr.mp.writeByte(dis.readByte()); // address_orig_bytes[i] + } + rr.mp.writeInt(dis.read()); //subaddressType + rr.mp.writeByte((byte) dis.read()); //subaddr_odd + subaddr_nbr_of_digits = (byte) dis.read(); + rr.mp.writeByte((byte) subaddr_nbr_of_digits); + for(int i=0; i < subaddr_nbr_of_digits; i++){ + rr.mp.writeByte(dis.readByte()); //subaddr_orig_bytes[i] + } + + bearerDataLength = dis.read(); + rr.mp.writeInt(bearerDataLength); + for(int i=0; i < bearerDataLength; i++){ + rr.mp.writeByte(dis.readByte()); //bearerData[i] + } + }catch (IOException ex){ + if (RILJ_LOGD) riljLog("sendSmsCdma: conversion from input stream to object failed: " + + ex); + } + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + send(rr); } public void deleteSmsOnSim(int index, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_DELETE_SMS_ON_SIM, response); - + + rr.mp.writeInt(1); + rr.mp.writeInt(index); + + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + + " " + index); + } + + send(rr); + } + + public void deleteSmsOnRuim(int index, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, + response); + rr.mp.writeInt(1); rr.mp.writeInt(index); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + index); } @@ -1052,17 +1148,35 @@ public final class RIL extends BaseCommands implements CommandsInterface public void writeSmsToSim(int status, String smsc, String pdu, Message response) { status = translateStatus(status); - + RILRequest rr = RILRequest.obtain(RIL_REQUEST_WRITE_SMS_TO_SIM, response); - + rr.mp.writeInt(status); rr.mp.writeString(pdu); rr.mp.writeString(smsc); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " - + requestToString(rr.mRequest) + + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + + " " + status); + } + + send(rr); + } + + public void writeSmsToRuim(int status, String pdu, Message response) { + status = translateStatus(status); + + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, + response); + + rr.mp.writeInt(status); + rr.mp.writeString(pdu); + + if (Config.LOGD) { + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + status); } @@ -1075,101 +1189,166 @@ public final class RIL extends BaseCommands implements CommandsInterface */ private int translateStatus(int status) { switch(status & 0x7) { - case SmsManager.STATUS_ON_SIM_READ: + case SmsManager.STATUS_ON_ICC_READ: return 1; - case SmsManager.STATUS_ON_SIM_UNREAD: + case SmsManager.STATUS_ON_ICC_UNREAD: return 0; - case SmsManager.STATUS_ON_SIM_SENT: + case SmsManager.STATUS_ON_ICC_SENT: return 3; - case SmsManager.STATUS_ON_SIM_UNSENT: + case SmsManager.STATUS_ON_ICC_UNSENT: return 2; } - + // Default to READ. return 1; } - public void - setupDefaultPDP(String apn, String user, String password, Message result) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SETUP_DEFAULT_PDP, result); + /** + * @deprecated + */ + public void + setupDefaultPDP(String apn, String user, String password, Message result) { + String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS + String profile = ""; //profile number, NULL for GSM/UMTS + setupDataCall(radioTechnology, profile, apn, user, + password, result); - rr.mp.writeInt(3); + } + + /** + * @deprecated + */ + public void + deactivateDefaultPDP(int cid, Message result) { + deactivateDataCall(cid, result); + } + + /** + * The preferred new alternative to setupDefaultPDP that is + * CDMA-compatible. + * + */ + public void + setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); + + rr.mp.writeInt(5); + + rr.mp.writeString(radioTechnology); + rr.mp.writeString(profile); rr.mp.writeString(apn); rr.mp.writeString(user); rr.mp.writeString(password); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + apn); - + send(rr); } public void - deactivateDefaultPDP(int cid, Message result) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DEFAULT_PDP, result); + deactivateDataCall(int cid, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DATA_CALL, result); rr.mp.writeInt(1); rr.mp.writeString(Integer.toString(cid)); - if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cid); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + cid); + send(rr); } public void - setRadioPower(boolean on, Message result) - { - RILRequest rr + setRadioPower(boolean on, Message result) { + //if radio is OFF set preferred NW type and cmda subscription + if(mInitialRadioStateChange) { + synchronized (mStateMonitor) { + if (!mState.isOn()) { + RILRequest rrPnt = RILRequest.obtain( + RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, null); + + rrPnt.mp.writeInt(1); + rrPnt.mp.writeInt(mNetworkMode); + if (RILJ_LOGD) riljLog(rrPnt.serialString() + "> " + + requestToString(rrPnt.mRequest) + " : " + mNetworkMode); + + send(rrPnt); + + RILRequest rrCs = RILRequest.obtain( + RIL_REQUEST_CDMA_SET_SUBSCRIPTION, null); + rrCs.mp.writeInt(1); + rrCs.mp.writeInt(mCdmaSubscription); + if (RILJ_LOGD) riljLog(rrCs.serialString() + "> " + + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription); + send(rrCs); + } + } + } + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result); rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void - setSuppServiceNotifications(boolean enable, Message result) - { - RILRequest rr + setSuppServiceNotifications(boolean enable, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, result); rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " - + requestToString(rr.mRequest)); + + requestToString(rr.mRequest)); send(rr); } - public void - acknowledgeLastIncomingSMS(boolean success, Message result) - { - RILRequest rr + public void + acknowledgeLastIncomingSMS(boolean success, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SMS_ACKNOWLEDGE, result); rr.mp.writeInt(1); rr.mp.writeInt(success ? 1 : 0); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - + public void - simIO (int command, int fileid, String path, int p1, int p2, int p3, - String data, String pin2, Message result) - { - RILRequest rr + acknowledgeLastIncomingCdmaSms(boolean success, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result); + + rr.mp.writeInt(success ? 0 : 1); //RIL_CDMA_SMS_ErrorClass + // cause code according to X.S004-550E + rr.mp.writeInt(39); //39 means other terminal problem; is not interpreted for success. + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + + public void + iccIO (int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, Message result) { + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIM_IO, result); - + rr.mp.writeInt(command); rr.mp.writeInt(fileid); rr.mp.writeString(path); @@ -1179,51 +1358,48 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(data); rr.mp.writeString(pin2); - if (RILJ_LOGD) riljLog(rr.serialString() + "> simIO: " + requestToString(rr.mRequest) - + " 0x" + Integer.toHexString(command) - + " 0x" + Integer.toHexString(fileid) + " " + if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest) + + " 0x" + Integer.toHexString(command) + + " 0x" + Integer.toHexString(fileid) + " " + p1 + "," + p2 + "," + p3); - + send(rr); } - + public void - getCLIR(Message result) - { - RILRequest rr + getCLIR(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CLIR, result); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void - setCLIR(int clirMode, Message result) - { - RILRequest rr + setCLIR(int clirMode, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CLIR, result); // count ints rr.mp.writeInt(1); rr.mp.writeInt(clirMode); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + clirMode); - + send(rr); } public void - queryCallWaiting(int serviceClass, Message response) - { - RILRequest rr + queryCallWaiting(int serviceClass, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_WAITING, response); rr.mp.writeInt(1); rr.mp.writeInt(serviceClass); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + serviceClass); @@ -1231,77 +1407,71 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - setCallWaiting(boolean enable, int serviceClass, Message response) - { - RILRequest rr + setCallWaiting(boolean enable, int serviceClass, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CALL_WAITING, response); - + rr.mp.writeInt(2); rr.mp.writeInt(enable ? 1 : 0); rr.mp.writeInt(serviceClass); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + enable + ", " + serviceClass); - + send(rr); } public void - setNetworkSelectionModeAutomatic(Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, + setNetworkSelectionModeAutomatic(Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - public void - setNetworkSelectionModeManual(String operatorNumeric, Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, + public void + setNetworkSelectionModeManual(String operatorNumeric, Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + operatorNumeric); rr.mp.writeString(operatorNumeric); - + send(rr); } - public void - getNetworkSelectionMode(Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, + public void + getNetworkSelectionMode(Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - public void - getAvailableNetworks(Message response) - { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, + public void + getAvailableNetworks(Message response) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void - setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message response) - { - RILRequest rr + setCallForward(int action, int cfReason, int serviceClass, + String number, int timeSeconds, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CALL_FORWARD, response); rr.mp.writeInt(action); @@ -1310,19 +1480,18 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(PhoneNumberUtils.toaFromString(number)); rr.mp.writeString(number); rr.mp.writeInt (timeSeconds); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) - + " " + action + " " + cfReason + " " + serviceClass + + " " + action + " " + cfReason + " " + serviceClass + timeSeconds); - + send(rr); } public void queryCallForwardStatus(int cfReason, int serviceClass, - String number, Message response) - { - RILRequest rr + String number, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, response); rr.mp.writeInt(2); // 2 is for query action, not in used anyway @@ -1331,7 +1500,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(PhoneNumberUtils.toaFromString(number)); rr.mp.writeString(number); rr.mp.writeInt (0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cfReason + " " + serviceClass); @@ -1339,8 +1508,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } public void - queryCLIP(Message response) - { + queryCLIP(Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CLIP, response); @@ -1351,11 +1519,10 @@ public final class RIL extends BaseCommands implements CommandsInterface public void - getBasebandVersion (Message response) - { - RILRequest rr + getBasebandVersion (Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_BASEBAND_VERSION, response); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); @@ -1363,14 +1530,13 @@ public final class RIL extends BaseCommands implements CommandsInterface public void queryFacilityLock (String facility, String password, int serviceClass, - Message response) - { + Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings - rr.mp.writeInt(3); + rr.mp.writeInt(3); rr.mp.writeString(facility); rr.mp.writeString(password); @@ -1382,8 +1548,7 @@ public final class RIL extends BaseCommands implements CommandsInterface public void setFacilityLock (String facility, boolean lockState, String password, - int serviceClass, Message response) - { + int serviceClass, Message response) { String lockString; RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response); @@ -1402,11 +1567,10 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - + public void - sendUSSD (String ussdString, Message response) - { - RILRequest rr + sendUSSD (String ussdString, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_USSD, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -1429,9 +1593,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } - public void resetRadio(Message result) - { - RILRequest rr + public void resetRadio(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RESET_RADIO, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -1439,13 +1602,12 @@ public final class RIL extends BaseCommands implements CommandsInterface send(rr); } - public void invokeOemRilRequestRaw(byte[] data, Message response) - { - RILRequest rr + public void invokeOemRilRequestRaw(byte[] data, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_RAW, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) - + "[" + SimUtils.bytesToHexString(data) + "]"); + + "[" + IccUtils.bytesToHexString(data) + "]"); rr.mp.writeByteArray(data); @@ -1453,9 +1615,8 @@ public final class RIL extends BaseCommands implements CommandsInterface } - public void invokeOemRilRequestStrings(String[] strings, Message response) - { - RILRequest rr + public void invokeOemRilRequestStrings(String[] strings, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_STRINGS, response); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -1592,29 +1753,53 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_LOCATION_UPDATES, response); rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + enable); - + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void getSmscAddress(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SMSC_ADDRESS, result); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setSmscAddress(String address, Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_SMSC_ADDRESS, result); + + rr.mp.writeInt(1); + rr.mp.writeString(address); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + address); + send(rr); } //***** Private Methods - private void sendScreenState(boolean on) - { + private void sendScreenState(boolean on) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SCREEN_STATE, null); rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); - + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on); - + send(rr); } - + protected void - onRadioAvailable() - { + onRadioAvailable() { // In case screen state was lost (due to process crash), // this ensures that the RIL knows the correct screen state. @@ -1633,13 +1818,18 @@ public final class RIL extends BaseCommands implements CommandsInterface case 2: newState = RadioState.SIM_NOT_READY; break; case 3: newState = RadioState.SIM_LOCKED_OR_ABSENT; break; case 4: newState = RadioState.SIM_READY; break; - default: + case 5: newState = RadioState.RUIM_NOT_READY; break; + case 6: newState = RadioState.RUIM_READY; break; + case 7: newState = RadioState.RUIM_LOCKED_OR_ABSENT; break; + case 8: newState = RadioState.NV_NOT_READY; break; + case 9: newState = RadioState.NV_READY; break; + + default: throw new RuntimeException( "Unrecognized RIL_RadioState: " +state); } if (mInitialRadioStateChange) { - mInitialRadioStateChange = false; if (newState.isOn()) { /* If this is our first notification, make sure the radio * is powered off. This gets the radio into a known state, @@ -1648,12 +1838,15 @@ public final class RIL extends BaseCommands implements CommandsInterface * and/or radio knowing. */ if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF"); - setRadioPower(false, null); - return; + setRadioPower(false, null); + } else { + if (DBG) Log.d(LOG_TAG, "Radio OFF @ init"); + setRadioState(newState); } + mInitialRadioStateChange = false; + } else { + setRadioState(newState); } - - setRadioState(newState); } /** @@ -1661,13 +1854,12 @@ public final class RIL extends BaseCommands implements CommandsInterface * a) There is outstanding RIL request sent to RIL deamon and no replied * b) There is a request waiting to be sent out. * - * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't + * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't * happen often. */ private void - acquireWakeLock() - { + acquireWakeLock() { synchronized (mWakeLock) { mWakeLock.acquire(); mRequestMessagesPending++; @@ -1679,8 +1871,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - releaseWakeLockIfDone() - { + releaseWakeLockIfDone() { synchronized (mWakeLock) { if (mWakeLock.isHeld() && (mRequestMessagesPending == 0) && @@ -1692,8 +1883,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - send(RILRequest rr) - { + send(RILRequest rr) { Message msg; msg = mSender.obtainMessage(EVENT_SEND, rr); @@ -1704,8 +1894,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - processResponse (Parcel p) - { + processResponse (Parcel p) { int type; type = p.readInt(); @@ -1714,15 +1903,12 @@ public final class RIL extends BaseCommands implements CommandsInterface processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { processSolicited (p); - } + } releaseWakeLockIfDone(); } - - - private RILRequest findAndRemoveRequestFromList(int serial) - { + private RILRequest findAndRemoveRequestFromList(int serial) { synchronized (mRequestsList) { for (int i = 0, s = mRequestsList.size() ; i < s ; i++) { RILRequest rr = mRequestsList.get(i); @@ -1738,8 +1924,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - processSolicited (Parcel p) - { + processSolicited (Parcel p) { int serial, error; boolean found = false; @@ -1751,7 +1936,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr = findAndRemoveRequestFromList(serial); if (rr == null) { - Log.w(LOG_TAG, "Unexpected solicited response! sn: " + Log.w(LOG_TAG, "Unexpected solicited response! sn: " + serial + " error: " + error); return; } @@ -1763,14 +1948,14 @@ public final class RIL extends BaseCommands implements CommandsInterface } Object ret; - + try {switch (rr.mRequest) { /* cat libs/telephony/ril_commands.h \ | egrep "^ *{RIL_" \ | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/' */ - case RIL_REQUEST_GET_SIM_STATUS: ret = responseSimStatus(p); break; + case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; case RIL_REQUEST_ENTER_SIM_PIN: ret = responseVoid(p); break; case RIL_REQUEST_ENTER_SIM_PUK: ret = responseVoid(p); break; case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseVoid(p); break; @@ -1796,8 +1981,8 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_DTMF: ret = responseVoid(p); break; case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break; - case RIL_REQUEST_SETUP_DEFAULT_PDP: ret = responseStrings(p); break; - case RIL_REQUEST_SIM_IO: ret = responseSIM_IO(p); break; + case RIL_REQUEST_SETUP_DATA_CALL: ret = responseStrings(p); break; + case RIL_REQUEST_SIM_IO: ret = responseICC_IO(p); break; case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break; case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break; case RIL_REQUEST_GET_CLIR: ret = responseInts(p); break; @@ -1810,7 +1995,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_GET_IMEI: ret = responseString(p); break; case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break; case RIL_REQUEST_ANSWER: ret = responseVoid(p); break; - case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: ret = responseVoid(p); break; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break; case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break; case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseVoid(p); break; case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break; @@ -1822,39 +2007,63 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break; case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break; case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break; - case RIL_REQUEST_SET_MUTE: ret =responseVoid(p); break; - case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; - case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; - case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: ret = responseInts(p); break; - case RIL_REQUEST_PDP_CONTEXT_LIST: ret = responseContextList(p); break; - case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; - case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; - case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; + case RIL_REQUEST_SET_MUTE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; + case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_DATA_CALL_LIST: ret = responseDataCallList(p); break; + case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; + case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; + case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break; - case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; - case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; - case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; - case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; - case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; - case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; - case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; - case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; - case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; - case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; - 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_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; + case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; + case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; + case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; + case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; + case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; + case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; + 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 = responseCellList(p); break; - case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; - + case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_SUBSCRIPTION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret = responseInts(p); break; + case RIL_REQUEST_SET_TTY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_TTY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_FLASH: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BURST_DTMF: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SEND_SMS: ret = responseSMS(p); break; + case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_BROADCAST_CONFIG: ret = responseBR_SMS_CNF(p); break; + case RIL_REQUEST_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCDMA_BR_CNF(p); break; + case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; + case RIL_REQUEST_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_VALIDATE_AKEY: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret = responseVoid(p); break; + case RIL_REQUEST_CDMA_SUBSCRIPTION: ret = responseStrings(p); break; + case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break; + case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break; + case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break; + case RIL_REQUEST_GET_SMSC_ADDRESS: ret = responseString(p); break; + case RIL_REQUEST_SET_SMSC_ADDRESS: ret = responseVoid(p); break; default: - throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); + throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); //break; }} catch (Throwable tr) { // Exceptions here usually mean invalid RIL responses - - Log.w(LOG_TAG, rr.serialString() + "< " - + requestToString(rr.mRequest) + " exception, possible invalid RIL response", tr); + + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, possible invalid RIL response", tr); if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, null, tr); @@ -1866,18 +2075,17 @@ public final class RIL extends BaseCommands implements CommandsInterface if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest) + " " + retToString(rr.mRequest, ret)); - + if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); rr.mResult.sendToTarget(); } - + rr.release(); } private String - retToString(int req, Object ret) - { + retToString(int req, Object ret) { if (ret == null) return ""; switch (req) { // Don't log these return values, for privacy's sake. @@ -1938,8 +2146,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private void - processUnsolicited (Parcel p) - { + processUnsolicited (Parcel p) { int response; Object ret; @@ -1961,7 +2168,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_ON_USSD: ret = responseStrings(p); break; case RIL_UNSOL_NITZ_TIME_RECEIVED: ret = responseString(p); break; case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseInts(p); break; - case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: ret = responseContextList(p);break; + case RIL_UNSOL_DATA_CALL_LIST_CHANGED: ret = responseDataCallList(p);break; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: ret = responseSuppServiceNotification(p); break; case RIL_UNSOL_STK_SESSION_END: ret = responseVoid(p); break; case RIL_UNSOL_STK_PROACTIVE_COMMAND: ret = responseString(p); break; @@ -1971,11 +2178,16 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break; case RIL_UNSOL_CALL_RING: ret = responseVoid(p); break; case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break; - default: - throw new RuntimeException("Unrecognized unsol response: " + response); + case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: ret = responseVoid(p); break; + case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: ret = responseCdmaSms(p); break; + case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: ret = responseString(p); break; + case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: ret = responseVoid(p); break; + case RIL_UNSOL_OEM_HOOK_RAW: ret = responseRaw(p); break; + default: + throw new RuntimeException("Unrecognized unsol response: " + response); //break; (implied) }} catch (Throwable tr) { - Log.e(LOG_TAG, "Exception processing unsol response: " + response + + Log.e(LOG_TAG, "Exception processing unsol response: " + response + "Exception:" + tr.toString()); return; } @@ -1984,7 +2196,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: /* has bonus radio state int */ setRadioStateFromRILInt(p.readInt()); - + if (RILJ_LOGD) unsljLogMore(response, mState.toString()); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: @@ -2009,7 +2221,7 @@ public final class RIL extends BaseCommands implements CommandsInterface SmsMessage sms; - sms = SmsMessage.newFromCMT(a); + sms = SmsMessage.newFromCMT(a); if (mSMSRegistrant != null) { mSMSRegistrant .notifyRegistrant(new AsyncResult(null, sms, null)); @@ -2041,7 +2253,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_ON_USSD: String[] resp = (String[])ret; - + if (resp.length < 2) { resp = new String[2]; resp[0] = ((String[])ret)[0]; @@ -2053,7 +2265,7 @@ public final class RIL extends BaseCommands implements CommandsInterface new AsyncResult (null, resp, null)); } break; - case RIL_UNSOL_NITZ_TIME_RECEIVED: + case RIL_UNSOL_NITZ_TIME_RECEIVED: if (RILJ_LOGD) unsljLogRet(response, ret); // has bonus long containing milliseconds since boot that the NITZ @@ -2066,7 +2278,7 @@ public final class RIL extends BaseCommands implements CommandsInterface result[1] = Long.valueOf(nitzReceiveTime); if (mNITZTimeRegistrant != null) { - + mNITZTimeRegistrant .notifyRegistrant(new AsyncResult (null, result, null)); } else { @@ -2074,22 +2286,21 @@ public final class RIL extends BaseCommands implements CommandsInterface mLastNITZTimeInfo = result; } break; - + case RIL_UNSOL_SIGNAL_STRENGTH: // Note this is set to "verbose" because it happens // frequently if (RILJ_LOGV) unsljLogvRet(response, ret); - + if (mSignalStrengthRegistrant != null) { mSignalStrengthRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } break; - case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: + case RIL_UNSOL_DATA_CALL_LIST_CHANGED: if (RILJ_LOGD) unsljLogRet(response, ret); - mPDPRegistrants - .notifyRegistrants(new AsyncResult(null, ret, null)); + mDataConnectionRegistrants.notifyRegistrants(new AsyncResult(null, ret, null)); break; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: @@ -2140,40 +2351,75 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_SIM_SMS_STORAGE_FULL: if (RILJ_LOGD) unsljLog(response); - if (mSimSmsFullRegistrant != null) { - mSimSmsFullRegistrant.notifyRegistrant(); + if (mIccSmsFullRegistrant != null) { + mIccSmsFullRegistrant.notifyRegistrant(); } break; - case RIL_UNSOL_SIM_REFRESH: + case RIL_UNSOL_SIM_REFRESH: if (RILJ_LOGD) unsljLogRet(response, ret); - if (mSimRefreshRegistrant != null) { - mSimRefreshRegistrant.notifyRegistrant( + if (mIccRefreshRegistrant != null) { + mIccRefreshRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } break; - - case RIL_UNSOL_CALL_RING: + + case RIL_UNSOL_CALL_RING: if (RILJ_LOGD) unsljLog(response); - + if (mRingRegistrant != null) { mRingRegistrant.notifyRegistrant(); } break; - + case RIL_UNSOL_RESTRICTED_STATE_CHANGED: if (RILJ_LOGD) unsljLogvRet(response, ret); if (mRestrictedStateRegistrant != null) { mRestrictedStateRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } + + case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: + if (mIccStatusChangedRegistrants != null) { + mIccStatusChangedRegistrants.notifyRegistrants(); + } + break; + + case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: + SmsMessage sms = (SmsMessage) ret; + + if (mSMSRegistrant != null) { + mSMSRegistrant + .notifyRegistrant(new AsyncResult(null, sms, null)); + } + break; + + case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: + // TODO T: waiting for SMS BC feature + break; + + case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: + if (Config.LOGD) { + if (RILJ_LOGD) riljLog("[UNSL]< RUIM_SMS_STORAGE_FULL"); + } + + if (mIccSmsFullRegistrant != null) { + mIccSmsFullRegistrant.notifyRegistrant(); + } + break; + + case RIL_UNSOL_OEM_HOOK_RAW: + if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[])ret)); + if (mUnsolOemHookRawRegistrant != null) { + mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, ret, null)); + } + break; } } private Object - responseInts(Parcel p) - { + responseInts(Parcel p) { int numInts; int response[]; @@ -2190,14 +2436,12 @@ public final class RIL extends BaseCommands implements CommandsInterface private Object - responseVoid(Parcel p) - { + responseVoid(Parcel p) { return null; } private Object - responseCallForward(Parcel p) - { + responseCallForward(Parcel p) { int numInfos; CallForwardInfo infos[]; @@ -2220,22 +2464,28 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseSuppServiceNotification(Parcel p) - { + responseSuppServiceNotification(Parcel p) { SuppServiceNotification notification = new SuppServiceNotification(); - + notification.notificationType = p.readInt(); notification.code = p.readInt(); notification.index = p.readInt(); notification.type = p.readInt(); notification.number = p.readString(); - + return notification; } - + private Object - responseString(Parcel p) - { + responseCdmaSms(Parcel p) { + SmsMessage sms; + sms = SmsMessage.newFromParcel(p); + + return sms; + } + + private Object + responseString(Parcel p) { String response; response = p.readString(); @@ -2244,8 +2494,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseStrings(Parcel p) - { + responseStrings(Parcel p) { int num; String response[]; @@ -2259,13 +2508,12 @@ public final class RIL extends BaseCommands implements CommandsInterface response[i] = p.readString(); } } - + return response; } private Object - responseRaw(Parcel p) - { + responseRaw(Parcel p) { int num; byte response[]; @@ -2275,8 +2523,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseSMS(Parcel p) - { + responseSMS(Parcel p) { int messageRef; String ackPDU; @@ -2290,46 +2537,110 @@ public final class RIL extends BaseCommands implements CommandsInterface private Object - responseSIM_IO(Parcel p) - { + responseICC_IO(Parcel p) { int sw1, sw2; byte data[] = null; Message ret; - + sw1 = p.readInt(); sw2 = p.readInt(); String s = p.readString(); - return new SimIoResult(sw1, sw2, s); + return new IccIoResult(sw1, sw2, s); } private Object - responseSimStatus(Parcel p) - { - int status; - - status = ((int[])responseInts(p))[0]; - switch (status){ - case RIL_SIM_ABSENT: return SimStatus.SIM_ABSENT; - case RIL_SIM_NOT_READY: return SimStatus.SIM_NOT_READY; - case RIL_SIM_READY: return SimStatus.SIM_READY; - case RIL_SIM_PIN: return SimStatus.SIM_PIN; - case RIL_SIM_PUK: return SimStatus.SIM_PUK; - case RIL_SIM_NETWORK_PERSONALIZATION: - return SimStatus.SIM_NETWORK_PERSONALIZATION; - default: - // Unrecognized SIM status. Treat it like a missing SIM. - Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status); - return SimStatus.SIM_ABSENT; + responseIccCardStatus(Parcel p) { + RadioState currentRadioState; + IccCardApplication ca; + + currentRadioState = getRadioState(); + + IccCardStatus status = new IccCardStatus(); + status.card_state = status.CardStateFromRILInt(p.readInt()); + status.universal_pin_state = status.PinStateFromRILInt(p.readInt()); + status.gsm_umts_subscription_app_index = p.readInt(); + status.cdma_subscription_app_index = p.readInt(); + status.num_applications = p.readInt(); + + // limit to maximum allowed applications + if (status.num_applications > IccCardStatus.CARD_MAX_APPS) { + status.num_applications = IccCardStatus.CARD_MAX_APPS; } - } + for (int i = 0 ; i < status.num_applications ; i++) { + ca = new IccCardApplication(); + ca.app_type = ca.AppTypeFromRILInt(p.readInt()); + ca.app_state = ca.AppStateFromRILInt(p.readInt()); + ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); + ca.aid = p.readString(); + ca.app_label = p.readString(); + ca.pin1_replaced = p.readInt(); + ca.pin1 = p.readInt(); + ca.pin2 = p.readInt(); + status.application.add(ca); + } + + // this is common for all radio technologies + if (!status.card_state.isCardPresent()) { + return IccStatus.ICC_ABSENT; + } + + // check radio technology + if( currentRadioState == RadioState.RADIO_OFF || + currentRadioState == RadioState.RADIO_UNAVAILABLE || + currentRadioState == RadioState.SIM_NOT_READY || + currentRadioState == RadioState.RUIM_NOT_READY || + currentRadioState == RadioState.NV_NOT_READY || + currentRadioState == RadioState.NV_READY ) { + return IccStatus.ICC_NOT_READY; + } + + if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.SIM_READY || + currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.RUIM_READY) { + + int index; + + // check for CDMA radio technology + if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.RUIM_READY) { + index = status.cdma_subscription_app_index; + } + else { + index = status.gsm_umts_subscription_app_index; + } + + // check if PIN required + if (status.application.get(index).app_state.isPinRequired()) { + return IccStatus.ICC_PIN; + } + if (status.application.get(index).app_state.isPukRequired()) { + return IccStatus.ICC_PUK; + } + if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) { + return IccStatus.ICC_NETWORK_PERSONALIZATION; + } + if (status.application.get(index).app_state.isAppReady()) { + return IccStatus.ICC_READY; + } + if (status.application.get(index).app_state.isAppNotReady()) { + return IccStatus.ICC_NOT_READY; + } + return IccStatus.ICC_NOT_READY; + } + + // Unrecognized ICC status. Treat it like a missing ICC. + Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status); + return IccStatus.ICC_ABSENT; + } private Object - responseCallList(Parcel p) - { + responseCallList(Parcel p) { int num; + int voiceSettings; ArrayList response; DriverCall dc; @@ -2338,17 +2649,26 @@ public final class RIL extends BaseCommands implements CommandsInterface for (int i = 0 ; i < num ; i++) { dc = new DriverCall(); - + dc.state = DriverCall.stateFromCLCC(p.readInt()); dc.index = p.readInt(); dc.TOA = p.readInt(); dc.isMpty = (0 != p.readInt()); dc.isMT = (0 != p.readInt()); dc.als = p.readInt(); - dc.isVoice = (0 == p.readInt()) ? false : true; + voiceSettings = p.readInt(); + dc.isVoice = (0 == voiceSettings) ? false : true; + + //dc.isVoicePrivacy = (0 != p.readInt()); + int voicePrivacy = p.readInt(); + dc.isVoicePrivacy = (0 != voicePrivacy); + dc.number = p.readString(); - dc.numberPresentation = DriverCall.presentationFromCLIP(p.readInt()); - + int np = p.readInt(); + dc.numberPresentation = DriverCall.presentationFromCLIP(np); + dc.name = p.readString(); + dc.namePresentation = p.readInt(); + // Make sure there's a leading + on addresses with a TOA // of 145 @@ -2356,6 +2676,16 @@ public final class RIL extends BaseCommands implements CommandsInterface dc.number, dc.TOA); response.add(dc); + + if ( RILConstants.CDMA_VOICE_PRIVACY == voiceSettings ) { + mVoicePrivacyOnRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is enabled: " + + Integer.toString(voiceSettings)); + } else { + mVoicePrivacyOffRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is disabled: " + + Integer.toString(voiceSettings)); + } } Collections.sort(response); @@ -2364,8 +2694,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseContextList(Parcel p) - { + responseDataCallList(Parcel p) { int num; ArrayList response; @@ -2376,7 +2705,7 @@ public final class RIL extends BaseCommands implements CommandsInterface PDPContextState pdp = new PDPContextState(); pdp.cid = p.readInt(); - pdp.active = p.readInt() == 0 ? false : true; + pdp.active = p.readInt(); pdp.type = p.readString(); pdp.apn = p.readString(); pdp.address = p.readString(); @@ -2388,14 +2717,13 @@ public final class RIL extends BaseCommands implements CommandsInterface } private Object - responseNetworkInfos(Parcel p) - { + responseNetworkInfos(Parcel p) { String strings[] = (String [])responseStrings(p); ArrayList ret; if (strings.length % 4 != 0) { throw new RuntimeException( - "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + strings.length + " strings, expected multible of 4"); } @@ -2409,37 +2737,78 @@ public final class RIL extends BaseCommands implements CommandsInterface strings[i+2], strings[i+3])); } - + 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; + } + private Object - responseCellList(Parcel p) - { - int num; - ArrayList response; - NeighboringCellInfo cell; + responseBR_SMS_CNF(Parcel p) { + // TODO + return null; + } - num = p.readInt(); - response = new ArrayList(num); + private Object + responseCDMA_BR_CNF(Parcel p) { + int numServiceCategories; + int response[]; - 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) { + numServiceCategories = p.readInt(); + + if (numServiceCategories == 0) { + int numInts; + numInts = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES * CDMA_BSI_NO_OF_INTS_STRUCT + 1; + response = new int[numInts]; + + // indicate that a zero length table was received + response[0] = 0; + //for all supported service categories set 'english' as default language + //and selection status to false + for (int i = 1, j = 1 + ; i <= (CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES + * CDMA_BSI_NO_OF_INTS_STRUCT) + ; i += CDMA_BSI_NO_OF_INTS_STRUCT, j++ ) { + response[i] = j; + response[i+1] = 1; + response[i+2] = 0; } + } else { + int numInts; + numInts = numServiceCategories * CDMA_BSI_NO_OF_INTS_STRUCT + 1; + response = new int[numInts]; + + response[0] = numServiceCategories; + for (int i = 1 ; i < numInts; i++) { + response[i] = p.readInt(); + } } return response; } - static String - requestToString(int request) - { + requestToString(int request) { /* cat libs/telephony/ril_commands.h \ | egrep "^ *{RIL_" \ @@ -2472,7 +2841,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_DTMF: return "DTMF"; case RIL_REQUEST_SEND_SMS: return "SEND_SMS"; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE"; - case RIL_REQUEST_SETUP_DEFAULT_PDP: return "SETUP_DEFAULT_PDP"; + case RIL_REQUEST_SETUP_DATA_CALL: return "SETUP_DATA_CALL"; case RIL_REQUEST_SIM_IO: return "SIM_IO"; case RIL_REQUEST_SEND_USSD: return "SEND_USSD"; case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD"; @@ -2486,7 +2855,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_GET_IMEI: return "GET_IMEI"; case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV"; case RIL_REQUEST_ANSWER: return "ANSWER"; - case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: return "DEACTIVATE_DEFAULT_PDP"; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "DEACTIVATE_DATA_CALL"; case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK"; case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK"; case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD"; @@ -2501,8 +2870,8 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_SET_MUTE: return "SET_MUTE"; case RIL_REQUEST_GET_MUTE: return "GET_MUTE"; case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP"; - case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: return "LAST_PDP_FAIL_CAUSE"; - case RIL_REQUEST_PDP_CONTEXT_LIST: return "PDP_CONTEXT_LIST"; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: return "LAST_DATA_CALL_FAIL_CAUSE"; + case RIL_REQUEST_DATA_CALL_LIST: return "DATA_CALL_LIST"; case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO"; case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW"; case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS"; @@ -2522,6 +2891,30 @@ public final class RIL extends BaseCommands implements CommandsInterface 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"; + case RIL_REQUEST_CDMA_SET_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SET_SUBSCRIPTION"; + case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: return "RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE"; + case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: return "RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE"; + case RIL_REQUEST_SET_TTY_MODE: return "RIL_REQUEST_SET_TTY_MODE"; + case RIL_REQUEST_QUERY_TTY_MODE: return "RIL_REQUEST_QUERY_TTY_MODE"; + case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: return "RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE"; + case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: return "RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE"; + case RIL_REQUEST_CDMA_FLASH: return "RIL_REQUEST_CDMA_FLASH"; + case RIL_REQUEST_CDMA_BURST_DTMF: return "RIL_REQUEST_CDMA_BURST_DTMF"; + case RIL_REQUEST_CDMA_SEND_SMS: return "RIL_REQUEST_CDMA_SEND_SMS"; + case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: return "RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE"; + case RIL_REQUEST_GET_BROADCAST_CONFIG: return "RIL_REQUEST_GET_BROADCAST_CONFIG"; + case RIL_REQUEST_SET_BROADCAST_CONFIG: return "RIL_REQUEST_SET_BROADCAST_CONFIG"; + case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG"; + case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG"; + case RIL_REQUEST_BROADCAST_ACTIVATION: return "RIL_REQUEST_BROADCAST_ACTIVATION"; + case RIL_REQUEST_CDMA_VALIDATE_AKEY: return "RIL_REQUEST_CDMA_VALIDATE_AKEY"; + case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: return "RIL_REQUEST_CDMA_BROADCAST_ACTIVATION"; + case RIL_REQUEST_CDMA_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SUBSCRIPTION"; + case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM"; + case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM"; + case RIL_REQUEST_DEVICE_IDENTITY: return "RIL_REQUEST_DEVICE_IDENTITY"; + case RIL_REQUEST_GET_SMSC_ADDRESS: return "RIL_REQUEST_GET_SMSC_ADDRESS"; + case RIL_REQUEST_SET_SMSC_ADDRESS: return "RIL_REQUEST_SET_SMSC_ADDRESS"; default: return ""; } } @@ -2545,7 +2938,7 @@ public final class RIL extends BaseCommands implements CommandsInterface 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_DATA_CALL_LIST_CHANGED: return "UNSOL_DATA_CALL_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"; @@ -2555,6 +2948,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH"; case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING"; case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "RIL_UNSOL_RESTRICTED_STATE_CHANGED"; + case RIL_UNSOL_OEM_HOOK_RAW: return "RIL_UNSOL_OEM_HOOK_RAW"; default: return ""; } } @@ -2583,4 +2977,140 @@ public final class RIL extends BaseCommands implements CommandsInterface riljLogv("[UNSL]< " + responseToString(response) + " " + retToString(response, ret)); } + + // ***** Methods for CDMA support + public void + getDeviceIdentity(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DEVICE_IDENTITY, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void + getCDMASubscription(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SUBSCRIPTION, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void setPhoneType(int phoneType) { //Set by CDMAPhone and GSMPhone constructor + mPhoneType = phoneType; + } + + /** + * {@inheritDoc} + */ + public void queryCdmaRoamingPreference(Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, response); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(cdmaRoamingType); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + cdmaRoamingType); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setCdmaSubscription(int cdmaSubscription , Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_CDMA_SET_SUBSCRIPTION, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(cdmaSubscription); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + cdmaSubscription); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void queryTTYModeEnabled(Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_QUERY_TTY_MODE, response); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void setTTYModeEnabled(boolean enable, Message response) { + RILRequest rr = RILRequest.obtain( + RILConstants.RIL_REQUEST_SET_TTY_MODE, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(enable ? 1 : 0); + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void + sendCDMAFeatureCode(String FeatureCode, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_FLASH, response); + + rr.mp.writeInt(1); + rr.mp.writeString(FeatureCode); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + FeatureCode); + + send(rr); + } + + public void getCdmaBroadcastConfig(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG, response); + + send(rr); + } + + public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, response); + + rr.mp.writeInt(configValuesArray[0]); + for(int i = 1; i <= (configValuesArray[0] * 3); i++) { + rr.mp.writeInt(configValuesArray[i]); + } + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + public void activateCdmaBroadcastSms(int activate, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_BROADCAST_ACTIVATION, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(activate); + + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java similarity index 55% rename from telephony/java/com/android/internal/telephony/gsm/RILConstants.java rename to telephony/java/com/android/internal/telephony/RILConstants.java index 4463b2085d6b7806fe6e3f3852b984ced9a0a28c..bcf51417aad8b4056d1acef5dd4162f86b8df591 100644 --- a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -14,29 +14,62 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -interface RILConstants -{ +public interface RILConstants { // From the top of ril.cpp int RIL_ERRNO_INVALID_RESPONSE = -1; // from RIL_Errno int SUCCESS = 0; - int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */ + int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */ int GENERIC_FAILURE = 2; - int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */ - int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */ - int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */ + int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */ + int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */ + int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */ int REQUEST_NOT_SUPPORTED = 6; int REQUEST_CANCELLED = 7; - int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in class C */ - int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to network */ - int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */ + int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in + class C */ + int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to + network */ + int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */ + + /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */ + int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ + int NETWORK_MODE_GSM_ONLY = 1; /* GSM only */ + int NETWORK_MODE_WCDMA_ONLY = 2; /* WCDMA only */ + int NETWORK_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NETWORK_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NETWORK_MODE_CDMA_NO_EVDO = 5; /* CDMA only */ + int NETWORK_MODE_EVDO_NO_CDMA = 6; /* EvDo only */ + int NETWORK_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int PREFERRED_NETWORK_MODE = NETWORK_MODE_GSM_ONLY; + + /* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */ + int SUBSCRIPTION_FROM_RUIM = 0; /* CDMA subscription from RUIM when available */ + int SUBSCRIPTION_FROM_NV = 1; /* CDMA subscription from NV */ + int PREFERRED_CDMA_SUBSCRIPTION = SUBSCRIPTION_FROM_NV; + + int CDMA_CELL_BROADCAST_SMS_DISABLED = 1; + int CDMA_CELL_BROADCAST_SMS_ENABLED = 0; + + int CDMA_PHONE = 0; + int GSM_PHONE = 1; + + int CDM_TTY_MODE_DISABLED = 0; + int CDM_TTY_MODE_ENABLED = 1; + + byte CDMA_VOICE_PRIVACY = 0x70; /* "p" value used in Ril_Call.isVoice if Privacy + is active */ + /* cat include/telephony/ril.h | \ egrep '^#define' | \ @@ -51,32 +84,32 @@ cat include/telephony/ril.h | \ int RIL_SIM_PIN = 3; int RIL_SIM_PUK = 4; int RIL_SIM_NETWORK_PERSONALIZATION = 5; - - /** - * No restriction at all including voice/SMS/USSD/SS/AV64 + + /** + * No restriction at all including voice/SMS/USSD/SS/AV64 * and packet data. - */ - int RIL_RESTRICTED_STATE_NONE = 0x00; - /** - * Block emergency call due to restriction. - * But allow all normal voice/SMS/USSD/SS/AV64. + */ + int RIL_RESTRICTED_STATE_NONE = 0x00; + /** + * Block emergency call due to restriction. + * But allow all normal voice/SMS/USSD/SS/AV64. */ int RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01; - /** - * Block all normal voice/SMS/USSD/SS/AV64 due to restriction. - * Only Emergency call allowed. + /** + * Block all normal voice/SMS/USSD/SS/AV64 due to restriction. + * Only Emergency call allowed. */ int RIL_RESTRICTED_STATE_CS_NORMAL = 0x02; - /** - * Block all voice/SMS/USSD/SS/AV64 + /** + * Block all voice/SMS/USSD/SS/AV64 * including emergency call due to restriction. */ int RIL_RESTRICTED_STATE_CS_ALL = 0x04; - /** - * Block packet data access due to restriction. - */ + /** + * Block packet data access due to restriction. + */ int RIL_RESTRICTED_STATE_PS_ALL = 0x10; - + int RIL_REQUEST_GET_SIM_STATUS = 1; int RIL_REQUEST_ENTER_SIM_PIN = 2; int RIL_REQUEST_ENTER_SIM_PUK = 3; @@ -103,7 +136,7 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_DTMF = 24; int RIL_REQUEST_SEND_SMS = 25; int RIL_REQUEST_SEND_SMS_EXPECT_MORE = 26; - int RIL_REQUEST_SETUP_DEFAULT_PDP = 27; + int RIL_REQUEST_SETUP_DATA_CALL = 27; int RIL_REQUEST_SIM_IO = 28; int RIL_REQUEST_SEND_USSD = 29; int RIL_REQUEST_CANCEL_USSD = 30; @@ -117,7 +150,7 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_GET_IMEI = 38; int RIL_REQUEST_GET_IMEISV = 39; int RIL_REQUEST_ANSWER = 40; - int RIL_REQUEST_DEACTIVATE_DEFAULT_PDP = 41; + int RIL_REQUEST_DEACTIVATE_DATA_CALL = 41; int RIL_REQUEST_QUERY_FACILITY_LOCK = 42; int RIL_REQUEST_SET_FACILITY_LOCK = 43; int RIL_REQUEST_CHANGE_BARRING_PASSWORD = 44; @@ -132,8 +165,8 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_SET_MUTE = 53; int RIL_REQUEST_GET_MUTE = 54; int RIL_REQUEST_QUERY_CLIP = 55; - int RIL_REQUEST_LAST_PDP_FAIL_CAUSE = 56; - int RIL_REQUEST_PDP_CONTEXT_LIST = 57; + int RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE = 56; + int RIL_REQUEST_DATA_CALL_LIST = 57; int RIL_REQUEST_RESET_RADIO = 58; int RIL_REQUEST_OEM_HOOK_RAW = 59; int RIL_REQUEST_OEM_HOOK_STRINGS = 60; @@ -153,6 +186,30 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE = 74; int RIL_REQUEST_GET_NEIGHBORING_CELL_IDS = 75; int RIL_REQUEST_SET_LOCATION_UPDATES = 76; + int RIL_REQUEST_CDMA_SET_SUBSCRIPTION = 77; + int RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE = 78; + int RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE = 79; + int RIL_REQUEST_SET_TTY_MODE = 80; + int RIL_REQUEST_QUERY_TTY_MODE = 81; + int RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE = 82; + int RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE = 83; + int RIL_REQUEST_CDMA_FLASH = 84; + int RIL_REQUEST_CDMA_BURST_DTMF = 85; + int RIL_REQUEST_CDMA_VALIDATE_AKEY = 86; + int RIL_REQUEST_CDMA_SEND_SMS = 87; + int RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE = 88; + int RIL_REQUEST_GET_BROADCAST_CONFIG = 89; + int RIL_REQUEST_SET_BROADCAST_CONFIG = 90; + int RIL_REQUEST_BROADCAST_ACTIVATION = 91; + int RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG = 92; + int RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG = 93; + int RIL_REQUEST_CDMA_BROADCAST_ACTIVATION = 94; + int RIL_REQUEST_CDMA_SUBSCRIPTION = 95; + int RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM = 96; + int RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM = 97; + int RIL_REQUEST_DEVICE_IDENTITY = 98; + int RIL_REQUEST_GET_SMSC_ADDRESS = 100; + int RIL_REQUEST_SET_SMSC_ADDRESS = 101; int RIL_UNSOL_RESPONSE_BASE = 1000; int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000; int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001; @@ -164,7 +221,7 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_ON_USSD_REQUEST = 1007; int RIL_UNSOL_NITZ_TIME_RECEIVED = 1008; int RIL_UNSOL_SIGNAL_STRENGTH = 1009; - int RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED = 1010; + int RIL_UNSOL_DATA_CALL_LIST_CHANGED = 1010; int RIL_UNSOL_SUPP_SVC_NOTIFICATION = 1011; int RIL_UNSOL_STK_SESSION_END = 1012; int RIL_UNSOL_STK_PROACTIVE_COMMAND = 1013; @@ -173,5 +230,14 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_SIM_SMS_STORAGE_FULL = 1016; int RIL_UNSOL_SIM_REFRESH = 1017; int RIL_UNSOL_CALL_RING = 1018; + int RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED = 1019; + int RIL_UNSOL_RESPONSE_CDMA_NEW_SMS = 1020; + int RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS = 1021; + int RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL = 1022; int RIL_UNSOL_RESTRICTED_STATE_CHANGED = 1023; + int RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE = 1024; + int RIL_UNSOL_CDMA_CALL_WAITING = 1025; + int RIL_UNSOL_CDMA_OTA_PROVISION_STATUS = 1026; + int RIL_UNSOL_CDMA_INFO_REC = 1027; + int RIL_UNSOL_OEM_HOOK_RAW = 1028; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java similarity index 57% rename from telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java rename to telephony/java/com/android/internal/telephony/SMSDispatcher.java index 558552409b253997c09477df42cf62b452fe5e0c..f2bd361ac1bb4ca4282712a494f90189dd7211b6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.app.Activity; import android.app.PendingIntent; @@ -32,19 +32,21 @@ import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; -import android.os.PowerManager; import android.provider.Telephony; -import android.provider.Settings; import android.provider.Telephony.Sms.Intents; -import android.telephony.gsm.SmsMessage; -import android.telephony.gsm.SmsManager; -import com.android.internal.telephony.WapPushOverSms; +import android.provider.Settings; +import android.telephony.SmsMessage; import android.telephony.ServiceState; import android.util.Config; -import com.android.internal.util.HexDump; import android.util.Log; import android.view.WindowManager; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsResponse; +import com.android.internal.telephony.WapPushOverSms; +import com.android.internal.util.HexDump; + import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.HashMap; @@ -52,58 +54,61 @@ import java.util.Random; import com.android.internal.R; -final class SMSDispatcher extends Handler { - private static final String TAG = "GSM"; +import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; +import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE; +import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU; +import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF; + + +public abstract class SMSDispatcher extends Handler { + private static final String TAG = "SMS"; - /** Default checking period for SMS sent without uesr permit */ + /** Default checking period for SMS sent without user permit */ private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; - /** Default number of SMS sent in checking period without uesr permit */ + /** Default number of SMS sent in checking period without user permit */ private static final int DEFAULT_SMS_MAX_COUNT = 100; /** Default timeout for SMS sent query */ private static final int DEFAULT_SMS_TIMOUEOUT = 6000; - private static final String[] RAW_PROJECTION = new String[] { + protected static final String[] RAW_PROJECTION = new String[] { "pdu", "sequence", }; static final int MAIL_SEND_SMS = 1; - static final int EVENT_NEW_SMS = 1; + static final protected int EVENT_NEW_SMS = 1; - static final int EVENT_SEND_SMS_COMPLETE = 2; + static final protected int EVENT_SEND_SMS_COMPLETE = 2; /** Retry sending a previously failed SMS message */ - static final int EVENT_SEND_RETRY = 3; + static final protected int EVENT_SEND_RETRY = 3; /** Status report received */ - static final int EVENT_NEW_SMS_STATUS_REPORT = 5; + static final protected int EVENT_NEW_SMS_STATUS_REPORT = 5; - /** SIM storage is full */ - static final int EVENT_SIM_FULL = 6; + /** SIM/RUIM storage is full */ + static final protected int EVENT_ICC_FULL = 6; /** SMS confirm required */ - static final int EVENT_POST_ALERT = 7; + static final protected int EVENT_POST_ALERT = 7; /** Send the user confirmed SMS */ - static final int EVENT_SEND_CONFIRMED_SMS = 8; + static final protected int EVENT_SEND_CONFIRMED_SMS = 8; /** Alert is timeout */ - static final int EVENT_ALERT_TIMEOUT = 9; + static final protected int EVENT_ALERT_TIMEOUT = 9; - private final GSMPhone mPhone; + protected Phone mPhone; + protected Context mContext; + protected ContentResolver mResolver; + protected CommandsInterface mCm; - private final WapPushOverSms mWapPush; + protected final WapPushOverSms mWapPush; - private final Context mContext; - - private final ContentResolver mResolver; - - private final CommandsInterface mCm; - - private final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); + protected final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); /** Maximum number of times to retry sending a failed SMS. */ private static final int MAX_SEND_RETRIES = 3; @@ -117,20 +122,15 @@ final class SMSDispatcher extends Handler { * CONCATENATED_16_BIT_REFERENCE message set. Should be * incremented for each set of concatenated messages. */ - private static int sConcatenatedRef; + protected static int sConcatenatedRef; private SmsCounter mCounter; private SmsTracker mSTracker; - /** Wake lock to ensure device stays awake while dispatching the SMS intent. */ - private PowerManager.WakeLock mWakeLock; - - /** - * Hold the wake lock for 5 seconds, which should be enough time for - * any receiver(s) to grab its own wake lock. - */ - private final int WAKE_LOCK_TIMEOUT = 5000; + private static SmsMessage mSmsMessage; + private static SmsMessageBase mSmsMessageBase; + private SmsMessageBase.SubmitPduBase mSubmitPduBase; /** * Implement the per-application based SMS control, which only allows @@ -177,6 +177,7 @@ final class SMSDispatcher extends Handler { while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) { sent.remove(0); } + if ( (sent.size() + smsWaiting) <= mMaxAllowed) { for (int i = 0; i < smsWaiting; i++ ) { @@ -188,7 +189,7 @@ final class SMSDispatcher extends Handler { } } - SMSDispatcher(GSMPhone phone) { + protected SMSDispatcher(PhoneBase phone) { mPhone = phone; mWapPush = new WapPushOverSms(phone); mContext = phone.getContext(); @@ -196,8 +197,6 @@ final class SMSDispatcher extends Handler { mCm = phone.mCM; mSTracker = null; - createWakelock(); - int check_period = Settings.Gservices.getInt(mResolver, Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); @@ -208,19 +207,30 @@ final class SMSDispatcher extends Handler { mCm.setOnNewSMS(this, EVENT_NEW_SMS, null); mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); - mCm.setOnSimSmsFull(this, EVENT_SIM_FULL, null); + mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null); // Don't always start message ref at 0. sConcatenatedRef = new Random().nextInt(256); } + public void dispose() { + mCm.unSetOnNewSMS(this); + mCm.unSetOnSmsStatus(this); + mCm.unSetOnIccSmsFull(this); + } + + protected void finalize() { + Log.d(TAG, "SMSDispatcher finalized"); + } + + /* TODO: Need to figure out how to keep track of status report routing in a * persistent manner. If the phone process restarts (reboot or crash), * we will lose this list and any status reports that come in after * will be dropped. */ /** Sent messages awaiting a delivery status report. */ - private final ArrayList deliveryPendingList = new ArrayList(); + protected final ArrayList deliveryPendingList = new ArrayList(); /** * Handles events coming from the phone stack. Overridden from handler. @@ -242,11 +252,8 @@ final class SMSDispatcher extends Handler { ar = (AsyncResult) msg.obj; - // FIXME unit test leaves cm == null. this should change - if (mCm != null) { // FIXME only acknowledge on store - mCm.acknowledgeLastIncomingSMS(true, null); - } + acknowledgeLastIncomingSms(true, null); if (ar.exception != null) { Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception); @@ -254,12 +261,12 @@ final class SMSDispatcher extends Handler { } sms = (SmsMessage) ar.result; - dispatchMessage(sms); + dispatchMessage(sms.mWrappedSmsMessage); break; case EVENT_SEND_SMS_COMPLETE: - // An outbound SMS has been sucessfully transferred, or failed. + // An outbound SMS has been successfully transferred, or failed. handleSendComplete((AsyncResult) msg.obj); break; @@ -271,8 +278,8 @@ final class SMSDispatcher extends Handler { handleStatusReport((AsyncResult)msg.obj); break; - case EVENT_SIM_FULL: - handleSimFull(); + case EVENT_ICC_FULL: + handleIccFull(); break; case EVENT_POST_ALERT: @@ -298,27 +305,14 @@ final class SMSDispatcher extends Handler { } } - private void createWakelock() { - PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher"); - mWakeLock.setReferenceCounted(true); - } - - private void sendBroadcast(Intent intent, String permission) { - // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any - // receivers time to take their own wake locks. - mWakeLock.acquire(WAKE_LOCK_TIMEOUT); - mContext.sendBroadcast(intent, permission); - } - /** * Called when SIM_FULL message is received from the RIL. Notifies interested * parties that SIM storage for SMS messages is full. */ - private void handleSimFull() { + private void handleIccFull(){ // broadcast SIM_FULL intent Intent intent = new Intent(Intents.SIM_FULL_ACTION); - sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS"); } /** @@ -328,34 +322,7 @@ final class SMSDispatcher extends Handler { * @param ar AsyncResult passed into the message handler. ar.result should * be a String representing the status report PDU, as ASCII hex. */ - private void handleStatusReport(AsyncResult ar) { - String pduString = (String) ar.result; - SmsMessage sms = SmsMessage.newFromCDS(pduString); - - if (sms != null) { - int messageRef = sms.messageRef; - for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { - SmsTracker tracker = deliveryPendingList.get(i); - if (tracker.mMessageRef == messageRef) { - // Found it. Remove from list and broadcast. - deliveryPendingList.remove(i); - PendingIntent intent = tracker.mDeliveryIntent; - Intent fillIn = new Intent(); - fillIn.putExtra("pdu", SimUtils.hexStringToBytes(pduString)); - try { - intent.send(mContext, Activity.RESULT_OK, fillIn); - } catch (CanceledException ex) {} - - // Only expect to see one tracker matching this messageref - break; - } - } - } - - if (mCm != null) { - mCm.acknowledgeLastIncomingSMS(true, null); - } - } + protected abstract void handleStatusReport(AsyncResult ar); /** * Called when SMS send completes. Broadcasts a sentIntent on success. @@ -366,7 +333,7 @@ final class SMSDispatcher extends Handler { * an SmsResponse instance if send was successful. ar.userObj * should be an SmsTracker instance. */ - private void handleSendComplete(AsyncResult ar) { + protected void handleSendComplete(AsyncResult ar) { SmsTracker tracker = (SmsTracker) ar.userObj; PendingIntent sentIntent = tracker.mSentIntent; @@ -414,7 +381,7 @@ final class SMSDispatcher extends Handler { } else if (tracker.mSentIntent != null) { // Done retrying; return an error to the app. try { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); + tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE); } catch (CanceledException ex) {} } } @@ -429,13 +396,13 @@ final class SMSDispatcher extends Handler { * POWER_OFF * @param tracker An SmsTracker for the current message. */ - private void handleNotInService(int ss, SmsTracker tracker) { + protected void handleNotInService(int ss, SmsTracker tracker) { if (tracker.mSentIntent != null) { try { if (ss == ServiceState.STATE_POWER_OFF) { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_RADIO_OFF); + tracker.mSentIntent.send(RESULT_ERROR_RADIO_OFF); } else { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE); + tracker.mSentIntent.send(RESULT_ERROR_NO_SERVICE); } } catch (CanceledException ex) {} } @@ -446,130 +413,14 @@ final class SMSDispatcher extends Handler { * * @param sms the incoming message from the phone */ - /* package */ void dispatchMessage(SmsMessage sms) { - - // If sms is null, means there was a parsing error. - // TODO: Should NAK this. - if (sms == null) { - return; - } - - boolean handled = false; - - // Special case the message waiting indicator messages - if (sms.isMWISetMessage()) { - mPhone.updateMessageWaitingIndicator(true); - - if (sms.isMwiDontStore()) { - handled = true; - } - - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator set SMS shouldStore=" - + !handled); - } - } else if (sms.isMWIClearMessage()) { - mPhone.updateMessageWaitingIndicator(false); - - if (sms.isMwiDontStore()) { - handled = true; - } + protected abstract void dispatchMessage(SmsMessageBase sms); - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator clear SMS shouldStore=" - + !handled); - } - } - - if (handled) { - return; - } - - // Parse the headers to see if this is partial, or port addressed - int referenceNumber = -1; - int count = 0; - int sequence = 0; - int destPort = -1; - - SmsHeader header = sms.getUserDataHeader(); - if (header != null) { - for (SmsHeader.Element element : header.getElements()) { - try { - switch (element.getID()) { - case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = data[0] & 0xff; - count = data[1] & 0xff; - sequence = data[2] & 0xff; - - // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence - // is zero, or sequence > count, ignore the entire element - if (count == 0 || sequence == 0 || sequence > count) { - referenceNumber = -1; - } - break; - } - - case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); - count = data[2] & 0xff; - sequence = data[3] & 0xff; - - // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence - // is zero, or sequence > count, ignore the entire element - if (count == 0 || sequence == 0 || sequence > count) { - referenceNumber = -1; - } - break; - } - - case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { - byte[] data = element.getData(); - - destPort = (data[0] & 0xff) << 8; - destPort |= (data[1] & 0xff); - - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - Log.e(TAG, "Bad element in header", e); - return; // TODO: NACK the message or something, don't just discard. - } - } - } - - if (referenceNumber == -1) { - // notify everyone of the message if it isn't partial - byte[][] pdus = new byte[1][]; - pdus[0] = sms.getPdu(); - - if (destPort != -1) { - if (destPort == SmsHeader.PORT_WAP_PUSH) { - mWapPush.dispatchWapPdu(sms.getUserData()); - } - // The message was sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destPort); - } else { - // It's a normal message, dispatch it - dispatchPdus(pdus); - } - } else { - // Process the message part - processMessagePart(sms, referenceNumber, sequence, count, destPort); - } - } /** * If this is the last part send the parts out to the application, otherwise * the part is stored for later processing. */ - private void processMessagePart(SmsMessage sms, int referenceNumber, + protected void processMessagePart(SmsMessageBase sms, int referenceNumber, int sequence, int count, int destinationPort) { // Lookup all other related parts StringBuilder where = new StringBuilder("reference_number ="); @@ -655,10 +506,11 @@ final class SMSDispatcher extends Handler { * * @param pdus The raw PDUs making up the message */ - private void dispatchPdus(byte[][] pdus) { + protected void dispatchPdus(byte[][] pdus) { Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION); intent.putExtra("pdus", pdus); - sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + mPhone.getContext().sendBroadcast( + intent, "android.permission.RECEIVE_SMS"); } /** @@ -667,11 +519,12 @@ final class SMSDispatcher extends Handler { * @param pdus The raw PDUs making up the message * @param port The destination port of the messages */ - private void dispatchPortAddressedPdus(byte[][] pdus, int port) { + protected void dispatchPortAddressedPdus(byte[][] pdus, int port) { Uri uri = Uri.parse("sms://localhost:" + port); Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri); intent.putExtra("pdus", pdus); - sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + mPhone.getContext().sendBroadcast( + intent, "android.permission.RECEIVE_SMS"); } @@ -700,114 +553,9 @@ final class SMSDispatcher extends Handler { * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). */ - void sendMultipartText(String destinationAddress, String scAddress, ArrayList parts, - ArrayList sentIntents, ArrayList deliveryIntents) { - - PendingIntent sentIntent = null; - - - int ss = mPhone.getServiceState().getState(); - - if (ss == ServiceState.STATE_IN_SERVICE) { - // Only check SMS sending limit while in service - if (sentIntents != null && sentIntents.size() > 0) { - sentIntent = sentIntents.get(0); - } - String appName = getAppNameByIntent(sentIntent); - if ( !mCounter.check(appName, parts.size())) { - HashMap map = new HashMap(); - map.put("destination", destinationAddress); - map.put("scaddress", scAddress); - map.put("parts", parts); - map.put("sentIntents", sentIntents); - map.put("deliveryIntents", deliveryIntents); - - SmsTracker multipartParameter = new SmsTracker(map, null, null); - - sendMessage(obtainMessage(EVENT_POST_ALERT, multipartParameter)); - return; - } - } - - sendMultipartTextWithPermit(destinationAddress, - scAddress, parts, sentIntents, deliveryIntents); - } - - /** - * Send a multi-part text based SMS which already passed SMS control check. - * - * It is the working function for sendMultipartText(). - * - * @param destinationAddress the address to send the message to - * @param scAddress is the service center address or null to use - * the current default SMSC - * @param parts an ArrayList of strings that, in order, - * comprise the original message - * @param sentIntents if not null, an ArrayList of - * PendingIntents (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be Activity.RESULT_OK for success, - * or one of these errors: - * RESULT_ERROR_GENERIC_FAILURE - * RESULT_ERROR_RADIO_OFF - * RESULT_ERROR_NULL_PDU. - * @param deliveryIntents if not null, an ArrayList of - * PendingIntents (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). - */ - private void sendMultipartTextWithPermit(String destinationAddress, - String scAddress, ArrayList parts, - ArrayList sentIntents, - ArrayList deliveryIntents) { - - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; - - // check if in service - int ss = mPhone.getServiceState().getState(); - if (ss != ServiceState.STATE_IN_SERVICE) { - for (int i = 0, count = parts.size(); i < count; i++) { - if (sentIntents != null && sentIntents.size() > i) { - sentIntent = sentIntents.get(i); - } - SmsTracker tracker = new SmsTracker(null, sentIntent, null); - handleNotInService(ss, tracker); - } - return; - } - - int ref = ++sConcatenatedRef & 0xff; - - for (int i = 0, count = parts.size(); i < count; i++) { - // build SmsHeader - byte[] data = new byte[3]; - data[0] = (byte) ref; // reference #, unique per message - data[1] = (byte) count; // total part count - data[2] = (byte) (i + 1); // 1-based sequence - SmsHeader header = new SmsHeader(); - header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); - - if (sentIntents != null && sentIntents.size() > i) { - sentIntent = sentIntents.get(i); - } - if (deliveryIntents != null && deliveryIntents.size() > i) { - deliveryIntent = deliveryIntents.get(i); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, header.toByteArray()); - - HashMap map = new HashMap(); - map.put("smsc", pdus.encodedScAddress); - map.put("pdu", pdus.encodedMessage); - - SmsTracker tracker = new SmsTracker(map, sentIntent, - deliveryIntent); - sendSms(tracker); - } - } + protected abstract void sendMultipartText(String destinationAddress, String scAddress, + ArrayList parts, ArrayList sentIntents, + ArrayList deliveryIntents); /** * Send a SMS @@ -829,12 +577,12 @@ final class SMSDispatcher extends Handler { * broadcast when the message is delivered to the recipient. The * raw pdu of the status report is in the extended data ("pdu"). */ - void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, PendingIntent deliveryIntent) { if (pdu == null) { if (sentIntent != null) { try { - sentIntent.send(SmsManager.RESULT_ERROR_NULL_PDU); + sentIntent.send(RESULT_ERROR_NULL_PDU); } catch (CanceledException ex) {} } return; @@ -865,7 +613,7 @@ final class SMSDispatcher extends Handler { * * An SmsTracker for the current message. */ - private void handleReachSentLimit(SmsTracker tracker) { + protected void handleReachSentLimit(SmsTracker tracker) { Resources r = Resources.getSystem(); @@ -886,7 +634,7 @@ final class SMSDispatcher extends Handler { DEFAULT_SMS_TIMOUEOUT); } - private String getAppNameByIntent(PendingIntent intent) { + protected String getAppNameByIntent(PendingIntent intent) { Resources r = Resources.getSystem(); return (intent != null) ? intent.getTargetPackage() : r.getString(R.string.sms_control_default_app_name); @@ -897,41 +645,53 @@ final class SMSDispatcher extends Handler { * * @param tracker holds the SMS message to send */ - private void sendSms(SmsTracker tracker) { - HashMap map = tracker.mData; - - byte smsc[] = (byte[]) map.get("smsc"); - byte pdu[] = (byte[]) map.get("pdu"); - - Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); - mCm.sendSMS(SimUtils.bytesToHexString(smsc), - SimUtils.bytesToHexString(pdu), reply); - } + protected abstract void sendSms(SmsTracker tracker); /** * Send the multi-part SMS based on multipart Sms tracker * * @param tracker holds the multipart Sms tracker ready to be sent */ - private void sendMultipartSms (SmsTracker tracker) { - ArrayList parts; - ArrayList sentIntents; - ArrayList deliveryIntents; - - HashMap map = tracker.mData; - - String destinationAddress = (String) map.get("destination"); - String scAddress = (String) map.get("scaddress"); - - parts = (ArrayList) map.get("parts"); - sentIntents = (ArrayList) map.get("sentIntents"); - deliveryIntents = (ArrayList) map.get("deliveryIntents"); - - sendMultipartTextWithPermit(destinationAddress, - scAddress, parts, sentIntents, deliveryIntents); + protected abstract void sendMultipartSms (SmsTracker tracker); + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + protected abstract void activateCellBroadcastSms(int activate, Message response); + + /** + * Query the current configuration of cell broadcast SMS. + * + * @param response + * Callback message contains the configuration from the modem on completion + * @see #setCellBroadcastConfig + */ + protected abstract void getCellBroadcastSmsConfig(Message response); + + /** + * Configure cell broadcast SMS. + * + * @param configValuesArray + * The first element defines the number of triples that follow. + * A triple is made up of the service category, the language identifier + * and a boolean that specifies whether the category is set active. + * @param response + * Callback message is empty on completion + */ + protected abstract void setCellBroadcastConfig(int[] configValuesArray, Message response); + + /** + * Send an acknowledge message. + * @param success indicates that last message was successfully received. + * @param response callback message sent when operation completes. + */ + protected abstract void acknowledgeLastIncomingSms(boolean success, Message response); - } - /** * Check if a SmsTracker holds multi-part Sms * @@ -942,19 +702,20 @@ final class SMSDispatcher extends Handler { HashMap map = tracker.mData; return ( map.get("parts") != null); } - + /** * Keeps track of an SMS that has been sent to the RIL, until it it has * successfully been sent, or we're done trying. * */ - static class SmsTracker { - HashMap mData; - int mRetryCount; - int mMessageRef; + static protected class SmsTracker { + // fields need to be public for derived SmsDispatchers + public HashMap mData; + public int mRetryCount; + public int mMessageRef; - PendingIntent mSentIntent; - PendingIntent mDeliveryIntent; + public PendingIntent mSentIntent; + public PendingIntent mDeliveryIntent; SmsTracker(HashMap data, PendingIntent sentIntent, PendingIntent deliveryIntent) { @@ -963,17 +724,21 @@ final class SMSDispatcher extends Handler { mDeliveryIntent = deliveryIntent; mRetryCount = 0; } - + } + + protected SmsTracker SmsTrackerFactory(HashMap data, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + return new SmsTracker(data, sentIntent, deliveryIntent); } private DialogInterface.OnClickListener mListener = - new DialogInterface.OnClickListener() { + new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - Log.d(TAG, "click YES to send out sms"); - sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); - } + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + Log.d(TAG, "click YES to send out sms"); + sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); } - }; + } + }; } diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java new file mode 100644 index 0000000000000000000000000000000000000000..7274e9972308e17f8675c325b63c8ae23321d1ce --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -0,0 +1,239 @@ +/* + * 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.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.telephony.ServiceState; + +/** + * {@hide} + */ +public abstract class ServiceStateTracker extends Handler { + /** + * The access technology currently in use: + * 0 = unknown + * 1 = GPRS only + * 2 = EDGE + * 3 = UMTS + */ + protected static final int DATA_ACCESS_UNKNOWN = 0; + protected static final int DATA_ACCESS_GPRS = 1; + protected static final int DATA_ACCESS_EDGE = 2; + protected static final int DATA_ACCESS_UMTS = 3; + protected static final int DATA_ACCESS_CDMA_IS95A = 4; + protected static final int DATA_ACCESS_CDMA_IS95B = 5; + protected static final int DATA_ACCESS_CDMA_1xRTT = 6; + protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7; + protected static final int DATA_ACCESS_CDMA_EvDo_A = 8; + //***** Instance Variables + + protected CommandsInterface cm; + + public ServiceState ss; + protected ServiceState newSS; + + // Used as a unique identifier to track requests associated with a poll + // and ignore stale responses.The value is a count-down of expected responses + // in this pollingContext + protected int[] pollingContext; + protected boolean mDesiredPowerState; + + protected boolean dontPollSignalStrength = false; // Default is to poll strength + // If we're getting unsolicited signal strength updates from the radio, + // set value to true and don't bother polling any more + + protected RegistrantList networkAttachedRegistrants = new RegistrantList(); + protected RegistrantList roamingOnRegistrants = new RegistrantList(); + protected RegistrantList roamingOffRegistrants = new RegistrantList(); + + //***** Constants + + protected static final boolean DBG = true; + + // signal strength poll rate + protected static final int POLL_PERIOD_MILLIS = 20 * 1000; + + // waiting period before recheck gprs and voice registration + public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; + + public static final int MAX_NUM_DATA_STATE_READS = 15; + public static final int DATA_STATE_POLL_SLEEP_MS = 100; + + //*****GSM events + protected static final int EVENT_RADIO_STATE_CHANGED = 1; + protected static final int EVENT_NETWORK_STATE_CHANGED = 2; + protected static final int EVENT_GET_SIGNAL_STRENGTH = 3; + protected static final int EVENT_POLL_STATE_REGISTRATION = 4; + protected static final int EVENT_POLL_STATE_GPRS = 5; + protected static final int EVENT_POLL_STATE_OPERATOR = 6; + protected static final int EVENT_POLL_SIGNAL_STRENGTH = 10; + protected static final int EVENT_NITZ_TIME = 11; + protected static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12; + protected static final int EVENT_RADIO_AVAILABLE = 13; + protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14; + protected static final int EVENT_GET_LOC_DONE = 15; + protected static final int EVENT_SIM_RECORDS_LOADED = 16; + protected static final int EVENT_SIM_READY = 17; + protected static final int EVENT_LOCATION_UPDATES_ENABLED = 18; + protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19; + protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20; + protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; + protected static final int EVENT_CHECK_REPORT_GPRS = 22; + protected static final int EVENT_RESTRICTED_STATE_CHANGED = 23; + + //*****CDMA events: + protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 24; + protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 25; + protected static final int EVENT_RUIM_READY = 26; + protected static final int EVENT_RUIM_RECORDS_LOADED = 27; + protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA = 28; + protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 29; + protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 30; + protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 31; + protected static final int EVENT_GET_LOC_DONE_CDMA = 32; + protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA = 33; + protected static final int EVENT_NV_LOADED = 34; + + //***** Time Zones + protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; + + // List of ISO codes for countries that can have an offset of GMT+0 + // when not in daylight savings time. This ignores some small places + // such as the Canary Islands (Spain) and Danmarkshavn (Denmark). + // The list must be sorted by code. + protected static final String[] GMT_COUNTRY_CODES = { + "bf", // Burkina Faso + "ci", // Cote d'Ivoire + "eh", // Western Sahara + "fo", // Faroe Islands, Denmark + "gh", // Ghana + "gm", // Gambia + "gn", // Guinea + "gw", // Guinea Bissau + "ie", // Ireland + "lr", // Liberia + "is", // Iceland + "ma", // Morocco + "ml", // Mali + "mr", // Mauritania + "pt", // Portugal + "sl", // Sierra Leone + "sn", // Senegal + "st", // Sao Tome and Principe + "tg", // Togo + "uk", // U.K + }; + + + //***** Constructors + public ServiceStateTracker() { + + } + + + /** + * Registration point for combined roaming on + * combined roaming is true when roaming is true and ONS differs SPN + * + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + public void registerForRoamingOn(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + roamingOnRegistrants.add(r); + + if (ss.getRoaming()) { + r.notifyRegistrant(); + } + } + + public void unregisterForRoamingOn(Handler h) { + roamingOnRegistrants.remove(h); + } + + /** + * Registration point for combined roaming off + * combined roaming is true when roaming is true and ONS differs SPN + * + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + public void registerForRoamingOff(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + roamingOffRegistrants.add(r); + + if (!ss.getRoaming()) { + r.notifyRegistrant(); + } + } + + public void unregisterForRoamingOff(Handler h) { + roamingOffRegistrants.remove(h); + } + + /** + * Reregister network through toggle perferred network type + * This is a work aorund to deregister and register network since there is + * no ril api to set COPS=2 (deregister) only. + * + * @param onComplete is dispatched when this is complete. it will be + * an AsyncResult, and onComplete.obj.exception will be non-null + * on failure. + */ + public void reRegisterNetwork(Message onComplete) { + cm.getPreferredNetworkType( + obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete)); + } + + + //***** Called from Phone + public void + setRadioPower(boolean power) { + mDesiredPowerState = power; + + setPowerStateToDesired(); + } + + + public void enableLocationUpdates() { + cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); + } + + public void disableLocationUpdates() { + cm.setLocationUpdates(false, null); + } + + //***** Overridden from Handler + public abstract void handleMessage(Message msg); + + //***** Protected abstract Methods + protected abstract void handlePollStateResult(int what, AsyncResult ar); + protected abstract void updateSpnDisplay(); + protected abstract void setPowerStateToDesired(); + + /** Cancel a pending (if any) pollState() operation */ + protected void cancelPollState() { + // This will effectively cancel the rest of the poll requests + pollingContext = new int[1]; + } +} diff --git a/telephony/java/com/android/internal/telephony/SmsAddress.java b/telephony/java/com/android/internal/telephony/SmsAddress.java new file mode 100644 index 0000000000000000000000000000000000000000..b3892cb0b342ac640f1ff9cc4777afb31e6595aa --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsAddress.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; + +public abstract class SmsAddress { + // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118 + // and C.S0005-D table 2.7.1.3.2.4-2 + public static final int TON_UNKNOWN = 0; + public static final int TON_INTERNATIONAL = 1; + public static final int TON_NATIONAL = 2; + public static final int TON_NETWORK = 3; + public static final int TON_SUBSCRIBER = 4; + public static final int TON_ALPHANUMERIC = 5; + public static final int TON_ABBREVIATED = 6; + + public int ton; + public String address; + public byte[] origBytes; + + /** + * Returns the address of the SMS message in String form or null if unavailable + */ + public String getAddressString() { + return address; + } + + /** + * Returns true if this is an alphanumeric address + */ + public boolean isAlphanumeric() { + return ton == TON_ALPHANUMERIC; + } + + /** + * Returns true if this is a network address + */ + public boolean isNetworkSpecific() { + return ton == TON_NETWORK; + } + + public boolean couldBeEmailGateway() { + // Some carriers seems to send email gateway messages in this form: + // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5 + // PID: 0x00, Data coding scheme 0x03 + // So we just attempt to treat any message from an address length <= 4 + // as an email gateway + + return address.length() <= 4; + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java similarity index 78% rename from telephony/java/com/android/internal/telephony/gsm/SmsHeader.java rename to telephony/java/com/android/internal/telephony/SmsHeader.java index 22366ecdb030ef29cf8c2438afd685439956724c..64b884efa0c564fb7082b90ba796a1ec0ae97547 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import com.android.internal.util.HexDump; @@ -24,8 +24,7 @@ import java.util.ArrayList; * This class represents a SMS user data header. * */ -public class SmsHeader -{ +public class SmsHeader { /** See TS 23.040 9.2.3.24 for description of this element ID. */ public static final int CONCATENATED_8_BIT_REFERENCE = 0x00; /** See TS 23.040 9.2.3.24 for description of this element ID. */ @@ -42,6 +41,7 @@ public class SmsHeader private byte[] m_data; private ArrayList m_elements = new ArrayList(); + public int nbrOfHeaders; /** * Creates an SmsHeader object from raw user data header bytes. @@ -49,36 +49,33 @@ public class SmsHeader * @param data is user data header bytes * @return an SmsHeader object */ - public static SmsHeader parse(byte[] data) - { + public static SmsHeader parse(byte[] data) { SmsHeader header = new SmsHeader(); header.m_data = data; int index = 0; - while (index < data.length) - { + header.nbrOfHeaders = 0; + while (index < data.length) { int id = data[index++] & 0xff; int length = data[index++] & 0xff; byte[] elementData = new byte[length]; System.arraycopy(data, index, elementData, 0, length); header.add(new Element(id, elementData)); index += length; + header.nbrOfHeaders++; } return header; } - public SmsHeader() - { - } + public SmsHeader() { } /** * Returns the list of SmsHeader Elements that make up the header. * * @return the list of SmsHeader Elements. */ - public ArrayList getElements() - { + public ArrayList getElements() { return m_elements; } @@ -87,14 +84,12 @@ public class SmsHeader * * @param element to add. */ - public void add(Element element) - { + public void add(Element element) { m_elements.add(element); } @Override - public String toString() - { + public String toString() { StringBuilder builder = new StringBuilder(); builder.append("UDH LENGTH: " + m_data.length + " octets"); @@ -104,40 +99,56 @@ public class SmsHeader for (Element e : getElements()) { builder.append(" 0x" + HexDump.toHexString((byte)e.getID()) + " - "); - switch (e.getID()) - { - case CONCATENATED_8_BIT_REFERENCE: - { + switch (e.getID()) { + case CONCATENATED_8_BIT_REFERENCE: { builder.append("Concatenated Short Message 8bit ref\n"); byte[] data = e.getData(); builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n"); + builder.append(HexDump.toHexString((byte)data.length) + + ") Bytes - Information Element\n"); builder.append(" " + data[0] + " : SM reference number\n"); builder.append(" " + data[1] + " : number of messages\n"); builder.append(" " + data[2] + " : this SM sequence number\n"); break; } - case CONCATENATED_16_BIT_REFERENCE: - { + case CONCATENATED_16_BIT_REFERENCE: { builder.append("Concatenated Short Message 16bit ref\n"); byte[] data = e.getData(); builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n"); - builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff) + - " : SM reference number\n"); + builder.append(HexDump.toHexString((byte)data.length) + + ") Bytes - Information Element\n"); + builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff) + + " : SM reference number\n"); builder.append(" " + data[2] + " : number of messages\n"); builder.append(" " + data[3] + " : this SM sequence number\n"); break; } - case APPLICATION_PORT_ADDRESSING_16_BIT: + case APPLICATION_PORT_ADDRESSING_8_BIT: { + builder.append("Application port addressing 8bit\n"); + byte[] data = e.getData(); + + builder.append(" " + data.length + " (0x"); + builder.append(HexDump.toHexString( + (byte)data.length) + ") Bytes - Information Element\n"); + + int source = (data[0] & 0xff); + builder.append(" " + source + " : DESTINATION port\n"); + + int dest = (data[1] & 0xff); + builder.append(" " + dest + " : SOURCE port\n"); + break; + } + + case APPLICATION_PORT_ADDRESSING_16_BIT: { builder.append("Application port addressing 16bit\n"); byte[] data = e.getData(); builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n"); + builder.append(HexDump.toHexString((byte)data.length) + + ") Bytes - Information Element\n"); int source = (data[0] & 0xff) << 8; source |= (data[1] & 0xff); @@ -149,8 +160,7 @@ public class SmsHeader break; } - default: - { + default: { builder.append("Unknown element\n"); break; } @@ -202,13 +212,11 @@ public class SmsHeader * See TS 23.040 9.2.3.24. * */ - public static class Element - { + public static class Element { private byte[] m_data; private int m_id; - public Element(int id, byte[] data) - { + public Element(int id, byte[] data) { m_id = id; m_data = data; } @@ -218,8 +226,7 @@ public class SmsHeader * * @return the IE identifier. */ - public int getID() - { + public int getID() { return m_id; } @@ -228,8 +235,7 @@ public class SmsHeader * * @return element data. */ - public byte[] getData() - { + public byte[] getData() { return m_data; } } diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java new file mode 100644 index 0000000000000000000000000000000000000000..1aad38d2aa82d51d621dcfa228b4d5fdd99a5c12 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -0,0 +1,374 @@ +/* + * 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.util.Log; +import com.android.internal.telephony.SmsHeader; +import java.util.Arrays; + +import static android.telephony.SmsMessage.MessageClass; + +/** + * Base class declaring the specific methods and members for SmsMessage. + * {@hide} + */ +public abstract class SmsMessageBase { + private static final String LOG_TAG = "SMS"; + + /** {@hide} The address of the SMSC. May be null */ + protected String scAddress; + + /** {@hide} The address of the sender */ + protected SmsAddress originatingAddress; + + /** {@hide} The message body as a string. May be null if the message isn't text */ + protected String messageBody; + + /** {@hide} */ + protected String pseudoSubject; + + /** {@hide} Non-null if this is an email gateway message */ + protected String emailFrom; + + /** {@hide} Non-null if this is an email gateway message */ + protected String emailBody; + + /** {@hide} */ + protected boolean isEmail; + + /** {@hide} */ + protected long scTimeMillis; + + /** {@hide} The raw PDU of the message */ + protected byte[] mPdu; + + /** {@hide} The raw bytes for the user data section of the message */ + protected byte[] userData; + + /** {@hide} */ + protected SmsHeader userDataHeader; + + // "Message Waiting Indication Group" + // 23.038 Section 4 + /** {@hide} */ + protected boolean isMwi; + + /** {@hide} */ + protected boolean mwiSense; + + /** {@hide} */ + protected boolean mwiDontStore; + + /** + * Indicates status for messages stored on the ICC. + */ + protected int statusOnIcc = -1; + + /** + * Record index of message in the EF. + */ + protected int indexOnIcc = -1; + + /** TP-Message-Reference - Message Reference of sent message. @hide */ + public int messageRef; + + public static abstract class SubmitPduBase { + public byte[] encodedScAddress; // Null if not applicable. + public byte[] encodedMessage; + + public String toString() { + return "SubmitPdu: encodedScAddress = " + + Arrays.toString(encodedScAddress) + + ", encodedMessage = " + + Arrays.toString(encodedMessage); + } + } + + /** + * Returns the address of the SMS service center that relayed this message + * or null if there is none. + */ + public String getServiceCenterAddress() { + return scAddress; + } + + /** + * Returns the originating address (sender) of this SMS message in String + * form or null if unavailable + */ + public String getOriginatingAddress() { + if (originatingAddress == null) { + return null; + } + + return originatingAddress.getAddressString(); + } + + /** + * Returns the originating address, or email from address if this message + * was from an email gateway. Returns null if originating address + * unavailable. + */ + public String getDisplayOriginatingAddress() { + if (isEmail) { + return emailFrom; + } else { + return getOriginatingAddress(); + } + } + + /** + * Returns the message body as a String, if it exists and is text based. + * @return message body is there is one, otherwise null + */ + public String getMessageBody() { + return messageBody; + } + + /** + * Returns the class of this message. + */ + public abstract MessageClass getMessageClass(); + + /** + * Returns the message body, or email message body if this message was from + * an email gateway. Returns null if message body unavailable. + */ + public String getDisplayMessageBody() { + if (isEmail) { + return emailBody; + } else { + return getMessageBody(); + } + } + + /** + * Unofficial convention of a subject line enclosed in parens empty string + * if not present + */ + public String getPseudoSubject() { + return pseudoSubject == null ? "" : pseudoSubject; + } + + /** + * Returns the service centre timestamp in currentTimeMillis() format + */ + public long getTimestampMillis() { + return scTimeMillis; + } + + /** + * Returns true if message is an email. + * + * @return true if this message came through an email gateway and email + * sender / subject / parsed body are available + */ + public boolean isEmail() { + return isEmail; + } + + /** + * @return if isEmail() is true, body of the email sent through the gateway. + * null otherwise + */ + public String getEmailBody() { + return emailBody; + } + + /** + * @return if isEmail() is true, email from address of email sent through + * the gateway. null otherwise + */ + public String getEmailFrom() { + return emailFrom; + } + + /** + * Get protocol identifier. + */ + public abstract int getProtocolIdentifier(); + + /** + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" + * SMS + */ + public abstract boolean isReplace(); + + /** + * Returns true for CPHS MWI toggle message. + * + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section + * B.4.2 + */ + public abstract boolean isCphsMwiMessage(); + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) clear message + */ + public abstract boolean isMWIClearMessage(); + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) set message + */ + public abstract boolean isMWISetMessage(); + + /** + * returns true if this message is a "Message Waiting Indication Group: + * Discard Message" notification and should not be stored. + */ + public abstract boolean isMwiDontStore(); + + /** + * returns the user data section minus the user data header if one was + * present. + */ + public byte[] getUserData() { + return userData; + } + + /** + * Returns an object representing the user data header + * + * @return an object representing the user data header + * + * {@hide} + */ + public SmsHeader getUserDataHeader() { + return userDataHeader; + } + + /** + * Returns the raw PDU for the message. + * + * @return the raw PDU for the message. + */ + public byte[] getPdu() { + return mPdu; + } + + /** + * For an SMS-STATUS-REPORT message, this returns the status field from + * the status report. This field indicates the status of a previously + * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a + * description of values. + * + * @return 0 indicates the previously sent message was received. + * See TS 23.040, 9.9.2.3.15 for a description of other possible + * values. + */ + public abstract int getStatus(); + + /** + * Return true iff the message is a SMS-STATUS-REPORT message. + */ + public abstract boolean isStatusReportMessage(); + + /** + * Returns true iff the TP-Reply-Path bit is set in + * this message. + */ + public abstract boolean isReplyPathPresent(); + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + */ + public int getStatusOnIcc() { + return statusOnIcc; + } + + /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + */ + public int getIndexOnIcc() { + return indexOnIcc; + } + + protected void parseMessageBody() { + if (originatingAddress.couldBeEmailGateway()) { + extractEmailAddressFromMessageBody(); + } + } + + /** + * Try to parse this message as an email gateway message -> Neither + * of the standard ways are currently supported: There are two ways + * specified in TS 23.040 Section 3.8 (not supported via this mechanism) - + * SMS message "may have its TP-PID set for internet electronic mail - MT + * SMS format: [] - "Depending on the + * nature of the gateway, the destination/origination address is either + * derived from the content of the SMS TP-OA or TP-DA field, or the + * TP-OA/TP-DA field contains a generic gateway address and the to/from + * address is added at the beginning as shown above." - multiple addreses + * separated by commas, no spaces - subject field delimited by '()' or '##' + * and '#' Section 9.2.3.24.11 + */ + protected void extractEmailAddressFromMessageBody() { + + /* + * a little guesswork here. I haven't found doc for this. + * the format could be either + * + * 1. [x@y][ ]/[subject][ ]/[body] + * -or- + * 2. [x@y][ ]/[body] + */ + int slash = 0, slash2 = 0, atSymbol = 0; + + try { + slash = messageBody.indexOf(" /"); + if (slash == -1) { + return; + } + + atSymbol = messageBody.indexOf('@'); + if (atSymbol == -1 || atSymbol > slash) { + return; + } + + emailFrom = messageBody.substring(0, slash); + + slash2 = messageBody.indexOf(" /", slash + 2); + + if (slash2 == -1) { + pseudoSubject = null; + emailBody = messageBody.substring(slash + 2); + } else { + pseudoSubject = messageBody.substring(slash + 2, slash2); + emailBody = messageBody.substring(slash2 + 2); + } + + isEmail = true; + } catch (Exception ex) { + Log.w(LOG_TAG, + "extractEmailAddressFromMessageBody: exception slash=" + + slash + ", atSymbol=" + atSymbol + ", slash2=" + + slash2, ex); + } + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl b/telephony/java/com/android/internal/telephony/SmsRawData.aidl similarity index 93% rename from telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl rename to telephony/java/com/android/internal/telephony/SmsRawData.aidl index 6f1a46dc9203fd5a4758428ebd29b42e7d9ba2c4..b0b3e4f93f578b0354bf5f4978774e1c040fe842 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl +++ b/telephony/java/com/android/internal/telephony/SmsRawData.aidl @@ -14,6 +14,6 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; parcelable SmsRawData; diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.java b/telephony/java/com/android/internal/telephony/SmsRawData.java similarity index 97% rename from telephony/java/com/android/internal/telephony/gsm/SmsRawData.java rename to telephony/java/com/android/internal/telephony/SmsRawData.java index a029d5ce59f8c1442884c84fad4899b13ae0ae8d..891d942b9a1345bb1805bf93c79f8c13084104c2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.java +++ b/telephony/java/com/android/internal/telephony/SmsRawData.java @@ -15,10 +15,10 @@ */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; /** * A parcelable holder class of byte[] for ISms aidl implementation @@ -50,7 +50,7 @@ public class SmsRawData implements Parcelable { public byte[] getBytes() { return data; } - + public int describeContents() { return 0; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsResponse.java b/telephony/java/com/android/internal/telephony/SmsResponse.java similarity index 88% rename from telephony/java/com/android/internal/telephony/gsm/SmsResponse.java rename to telephony/java/com/android/internal/telephony/SmsResponse.java index c005b5fa6612f31161197d0ce88ed9445fa8313a..3c4df563000e34190515bd7f7d9ed26f83deb4e9 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsResponse.java +++ b/telephony/java/com/android/internal/telephony/SmsResponse.java @@ -14,20 +14,20 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * Object returned by the RIL upon successful completion of sendSMS. * Contains message reference and ackPdu. * */ -class SmsResponse { +public class SmsResponse { /** Message reference of the just-sent SMS. */ int messageRef; /** ackPdu for the just-sent SMS. */ String ackPdu; - SmsResponse(int messageRef, String ackPdu) { + public SmsResponse(int messageRef, String ackPdu) { this.messageRef = messageRef; this.ackPdu = ackPdu; } diff --git a/telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java similarity index 92% rename from telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java rename to telephony/java/com/android/internal/telephony/TelephonyEventLog.java index 1e583f0b9f9e8a1bcf9e68d324e64f76c9b70864..97f9d7d450cf1fa1b3a8756914593e46a8db3e88 100644 --- a/telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java +++ b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /* This class contains the details related to Telephony Event Logging */ public final class TelephonyEventLog { @@ -28,6 +28,6 @@ public final class TelephonyEventLog { public static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105; public static final int EVENT_LOG_CALL_DROP = 50106; public static final int EVENT_LOG_CGREG_FAIL = 50107; - public static final int EVENT_DATA_STATE_RADIO_OFF = 50108; + public static final int EVENT_LOG_DATA_STATE_RADIO_OFF = 50108; public static final int EVENT_LOG_PDP_NETWORK_DROP = 50109; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 9219e7aa72d86da8649e5547740d8d4f99d6e00e..c3422339c0db2d68ac4962d824e8ab43a7b2f897 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -35,6 +35,24 @@ public class TelephonyIntents { */ public static final String ACTION_SERVICE_STATE_CHANGED = "android.intent.action.SERVICE_STATE"; + /** + *

            Broadcast Action: The radio technology has changed. The intent will have the following + * extra values:

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

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

            + * Requires no permission. + */ + public static final String ACTION_RADIO_TECHNOLOGY_CHANGED + = "android.intent.action.RADIO_TECHNOLOGY"; /** * Broadcast Action: The phone's signal strength has changed. The intent will have the @@ -47,7 +65,7 @@ public class TelephonyIntents { *

            • 0 means "-113 dBm or less".
            • 31 means "-51 dBm or greater".
            * *
          - * + * *

          * You can not receive this through components declared * in manifests, only by exlicitly registering for it with diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 6aa90f19d01ae5ac21f61b08a4a92397fcd0e815..396b42d6f95db0355584dd11f8bf7b91b320a5d7 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -26,8 +26,11 @@ public interface TelephonyProperties { //****** Baseband and Radio Interface version - /** - * Baseband version + //TODO T: property strings do not have to be gsm specific + // change gsm.*operator.*" properties to "operator.*" properties + + /** + * Baseband version * Availability: property is available any time radio is on */ static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband"; @@ -47,6 +50,12 @@ public interface TelephonyProperties */ static final String PROPERTY_OPERATOR_NUMERIC = "gsm.operator.numeric"; + /** 'true' if the device is on a manually selected network + * + * Availability: when registered to a network + */ + static final String PROPERTY_OPERATOR_ISMANUAL = "operator.ismanual"; + /** 'true' if the device is considered roaming on this network for GSM * purposes. * Availability: when registered to a network @@ -60,7 +69,7 @@ public interface TelephonyProperties static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country"; //****** SIM Card - /** + /** * One of "UNKNOWN" "ABSENT" "PIN_REQUIRED" * "PUK_REQUIRED" "NETWORK_LOCKED" or "READY" */ @@ -70,15 +79,15 @@ public interface TelephonyProperties * provider of the SIM. 5 or 6 decimal digits. * Availablity: SIM state must be "READY" */ - static String PROPERTY_SIM_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; + static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; - /** PROPERTY_SIM_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. + /** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. * Availablity: SIM state must be "READY" */ - static String PROPERTY_SIM_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; + static String PROPERTY_ICC_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; /** ISO country code equivalent for the SIM provider's country code*/ - static String PROPERTY_SIM_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country"; + static String PROPERTY_ICC_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country"; /** * Indicates the available radio technology. Values include: "unknown", diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java index 2b70162aaf7615f104b4087bbc8d55709264dc4c..98899c903684e13de1a20c343886e8678d35adf0 100644 --- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java +++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java @@ -22,7 +22,6 @@ import android.os.PowerManager; import android.provider.Telephony.Sms.Intents; import android.util.Config; import android.util.Log; -import com.android.internal.telephony.gsm.SimUtils; /** @@ -44,6 +43,7 @@ public class WapPushOverSms { private final int WAKE_LOCK_TIMEOUT = 5000; public WapPushOverSms(Phone phone) { + mContext = phone.getContext(); createWakelock(); } @@ -56,7 +56,7 @@ public class WapPushOverSms { */ public void dispatchWapPdu(byte[] pdu) { - if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + SimUtils.bytesToHexString(pdu)); + if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu)); int index = 0; int transactionId = pdu[index++] & 0xFF; @@ -225,3 +225,4 @@ public class WapPushOverSms { mContext.sendBroadcast(intent, permission); } } + diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java new file mode 100755 index 0000000000000000000000000000000000000000..8ffb7ecc44c7aa098e5a7a647d4f355e0e39cd0c --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -0,0 +1,911 @@ +/* + * 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.cdma; + +import android.content.Context; +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.provider.Settings; +import android.telephony.CellLocation; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; +import android.text.TextUtils; +import android.util.Log; + +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; + +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.IccSmsInterfaceManager; +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.PhoneProxy; +import com.android.internal.telephony.PhoneSubInfo; +import com.android.internal.telephony.RILConstants; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@hide} + */ +public class CDMAPhone extends PhoneBase { + static final String LOG_TAG = "CDMA"; + private static final boolean LOCAL_DEBUG = true; + + //***** Instance Variables + CdmaCallTracker mCT; + CdmaSMSDispatcher mSMS; + CdmaServiceStateTracker mSST; + CdmaDataConnectionTracker mDataConnection; + RuimFileHandler mRuimFileHandler; + RuimRecords mRuimRecords; + RuimCard mRuimCard; + MyHandler h; + RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager; + RuimSmsInterfaceManager mRuimSmsInterfaceManager; + PhoneSubInfo mSubInfo; + + protected RegistrantList mNvLoadedRegistrants = new RegistrantList(); + private String mEsn; + private String mMeid; + + Registrant mPostDialHandler; + + + //***** Constructors + public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { + this(context,ci,notifier, false); + } + + public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, + boolean unitTestMode) { + super(notifier, context, unitTestMode); + + h = new MyHandler(); + mCM = ci; + + mCM.setPhoneType(RILConstants.CDMA_PHONE); + mCT = new CdmaCallTracker(this); + mSST = new CdmaServiceStateTracker (this); + mSMS = new CdmaSMSDispatcher(this); + mIccFileHandler = new RuimFileHandler(this); + mRuimRecords = new RuimRecords(this); + mDataConnection = new CdmaDataConnectionTracker (this); + mRuimCard = new RuimCard(this); + mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); + mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this); + mSubInfo = new PhoneSubInfo(this); + + mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); + mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null); + mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mCM.registerForOn(h, EVENT_RADIO_ON, null); + mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); + mCM.setOnCallRing(h, EVENT_CALL_RING, null); + mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); + mCM.registerForNVReady(h, EVENT_NV_READY, null); + + //Change the system setting + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE); + } + + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + + //Unregister from all former registered events + mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED + mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE + mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(h); //EVENT_RADIO_ON + mCM.unregisterForNVReady(h); //EVENT_NV_READY + mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnSuppServiceNotification(h); + mCM.unSetOnCallRing(h); + + //Force all referenced classes to unregister their former registered events + mCT.dispose(); + mDataConnection.dispose(); + mSST.dispose(); + mSMS.dispose(); + mIccFileHandler.dispose(); // instance of RuimFileHandler + mRuimRecords.dispose(); + mRuimCard.dispose(); + mRuimPhoneBookInterfaceManager.dispose(); + mRuimSmsInterfaceManager.dispose(); + mSubInfo.dispose(); + } + } + + public void removeReferences() { + this.mRuimPhoneBookInterfaceManager = null; + this.mRuimSmsInterfaceManager = null; + this.mSMS = null; + this.mSubInfo = null; + this.mRuimRecords = null; + this.mIccFileHandler = null; + this.mRuimCard = null; + this.mDataConnection = null; + this.mCT = null; + this.mSST = null; + } + + protected void finalize() { + if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized"); + } + + + //***** Overridden from Phone + public ServiceState getServiceState() { + return mSST.ss; + } + + public Phone.State + getState() { + return mCT.state; + } + + public String + getPhoneName() { + return "CDMA"; + } + + public boolean canTransfer() { + Log.e(LOG_TAG, "canTransfer: not possible in CDMA"); + return false; + } + + public CdmaCall + getRingingCall() { + return mCT.ringingCall; + } + + public void setMute(boolean muted) { + mCT.setMute(muted); + } + + public boolean getMute() { + return mCT.getMute(); + } + + public void conference() throws CallStateException { + // three way calls in CDMA will be handled by feature codes + Log.e(LOG_TAG, "conference: not possible in CDMA"); + } + + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + this.mCM.setPreferredVoicePrivacy(enable, onComplete); + } + + public void getEnhancedVoicePrivacy(Message onComplete) { + this.mCM.getPreferredVoicePrivacy(onComplete); + } + + public void clearDisconnected() { + mCT.clearDisconnected(); + } + + public DataActivityState getDataActivityState() { + DataActivityState ret = DataActivityState.NONE; + + if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { + + switch (mDataConnection.getActivity()) { + case DATAIN: + ret = DataActivityState.DATAIN; + break; + + case DATAOUT: + ret = DataActivityState.DATAOUT; + break; + + case DATAINANDOUT: + ret = DataActivityState.DATAINANDOUT; + break; + } + } + return ret; + } + + /*package*/ void + notifySignalStrength() { + mNotifier.notifySignalStrength(this); + } + + public Connection + dial (String dialString) throws CallStateException { + // Need to make sure dialString gets parsed properly + String newDialString = PhoneNumberUtils.stripSeparators(dialString); + + if (!mCT.foregroundCall.isIdle()) { + FeatureCode fc = FeatureCode.newFromDialString(newDialString, this); + if (fc != null) { + //mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); + fc.processCode(); + } else { + FeatureCode digits = new FeatureCode(this); + // use dial number as poundString + digits.poundString = newDialString; + digits.processCode(); + } + return null; + } else { + return mCT.dial(newDialString); + } + } + + + public int getSignalStrengthASU() { + return mSST.rssi == 99 ? -1 : mSST.rssi; + } + + public boolean + getMessageWaitingIndicator() { + return mRuimRecords.getVoiceMessageWaiting(); + } + + public List + getPendingMmiCodes() { + Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!"); + return null; + } + + public void registerForSuppServiceNotification( + Handler h, int what, Object obj) { + Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!"); + } + + public CdmaCall getBackgroundCall() { + return mCT.backgroundCall; + } + + public String getGateway(String apnType) { + return mDataConnection.getGateway(); + } + + public boolean handleInCallMmiCommands(String dialString) { + Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!"); + return false; + } + + public int enableApnType(String type) { + // This request is mainly used to enable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to enableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_ALREADY_ACTIVE; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + public int disableApnType(String type) { + // This request is mainly used to disable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to disableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_REQUEST_STARTED; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + public String getActiveApn() { + Log.d(LOG_TAG, "Request to getActiveApn()"); + return null; + } + + public void + setNetworkSelectionModeAutomatic(Message response) { + Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!"); + } + + public void unregisterForSuppServiceNotification(Handler h) { + Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!"); + } + + public void + acceptCall() throws CallStateException { + mCT.acceptCall(); + } + + public void + rejectCall() throws CallStateException { + mCT.rejectCall(); + } + + public void + switchHoldingAndActive() throws CallStateException { + mCT.switchWaitingOrHoldingAndActive(); + } + + public String getLine1Number() { + return mRuimRecords.getMdnNumber(); + } + + public void getCallWaiting(Message onComplete) { + mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); + } + + public void + setRadioPower(boolean power) { + mSST.setRadioPower(power); + } + + public String getEsn() { + return mEsn; + } + + public String getMeid() { + return mMeid; + } + + //returns MEID in CDMA + public String getDeviceId() { + return getMeid(); + } + + public String getDeviceSvn() { + Log.d(LOG_TAG, "getDeviceSvn(): return 0"); + return "0"; + } + + public String getSubscriberId() { + Log.e(LOG_TAG, "method getSubscriberId for IMSI is NOT supported in CDMA!"); + return null; + } + + public boolean canConference() { + Log.e(LOG_TAG, "canConference: not possible in CDMA"); + return false; + } + + public String getInterfaceName(String apnType) { + return mDataConnection.getInterfaceName(); + } + + public CellLocation getCellLocation() { + return mSST.cellLoc; + } + + public boolean disableDataConnectivity() { + return mDataConnection.setDataEnabled(false); + } + + public CdmaCall getForegroundCall() { + return mCT.foregroundCall; + } + + public void + selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network, + Message response) { + Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA"); + } + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { + Log.e(LOG_TAG, "setOnPostDialCharacter: not possible in CDMA"); + } + + public boolean handlePinMmi(String dialString) { + Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!"); + return false; + } + + public boolean isDataConnectivityPossible() { + boolean noData = mDataConnection.getDataEnabled() && + getDataConnectionState() == DataState.DISCONNECTED; + return !noData && getIccCard().getState() == IccCard.State.READY && + getServiceState().getState() == ServiceState.STATE_IN_SERVICE && + (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); + } + + public void setLine1Number(String alphaTag, String number, Message onComplete) { + Log.e(LOG_TAG, "setLine1Number: not possible in CDMA"); + } + + public String[] getDnsServers(String apnType) { + return mDataConnection.getDnsServers(); + } + + public IccCard getIccCard() { + return mRuimCard; + } + + public String getIccSerialNumber() { + return mRuimRecords.iccid; + } + + public void setCallWaiting(boolean enable, Message onComplete) { + Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!"); + } + + public void updateServiceLocation(Message response) { + mSST.getLacAndCid(response); + } + + public void setDataRoamingEnabled(boolean enable) { + mDataConnection.setDataOnRoamingEnabled(enable); + } + + public String getIpAddress(String apnType) { + return mDataConnection.getIpAddress(); + } + + public void + getNeighboringCids(Message response) { + // WINK:TODO: implement after Cupcake merge + mCM.getNeighboringCids(response); // workaround. + } + + public DataState getDataConnectionState() { + DataState ret = DataState.DISCONNECTED; + + if ((SystemProperties.get("adb.connected", "").length() > 0) + && (SystemProperties.get("android.net.use-adb-networking", "") + .length() > 0)) { + // We're connected to an ADB host and we have USB networking + // turned on. No matter what the radio state is, + // we report data connected + + ret = DataState.CONNECTED; + } else if (mSST == null) { + // Radio Technology Change is ongoning, dispose() and removeReferences() have + // already been called + + ret = DataState.DISCONNECTED; + } else if (mSST.getCurrentCdmaDataConnectionState() + == ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { + // If we're out of service, open TCP sockets may still work + // but no data will flow + ret = DataState.DISCONNECTED; + } else { + switch (mDataConnection.getState()) { + case FAILED: + case IDLE: + ret = DataState.DISCONNECTED; + break; + + case CONNECTED: + case DISCONNECTING: + if ( mCT.state != Phone.State.IDLE + && !mSST.isConcurrentVoiceAndData()) { + ret = DataState.SUSPENDED; + } else { + ret = DataState.CONNECTED; + } + break; + + case INITING: + case CONNECTING: + case SCANNING: + ret = DataState.CONNECTING; + break; + } + } + + return ret; + } + + public void sendUssdResponse(String ussdMessge) { + Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA"); + } + + public void sendDtmf(char c) { + if (!PhoneNumberUtils.is12Key(c)) { + Log.e(LOG_TAG, + "sendDtmf called with invalid character '" + c + "'"); + } else { + if (mCT.state == Phone.State.OFFHOOK) { + mCM.sendDtmf(c, null); + } + } + } + + public void startDtmf(char c) { + if (!PhoneNumberUtils.is12Key(c)) { + Log.e(LOG_TAG, + "startDtmf called with invalid character '" + c + "'"); + } else { + mCM.startDtmf(c, null); + } + } + + public void stopDtmf() { + mCM.stopDtmf(null); + } + + public void getAvailableNetworks(Message response) { + Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); + } + + public String[] getActiveApnTypes() { + String[] result; + Log.d(LOG_TAG, "Request to getActiveApn()"); + result = new String[1]; + result[0] = Phone.APN_TYPE_DEFAULT; + return result; + } + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { + Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); + } + + public void enableLocationUpdates() { + mSST.enableLocationUpdates(); + } + + /** + * @deprecated + */ + public void getPdpContextList(Message response) { + getDataCallList(response); + } + + public void getDataCallList(Message response) { + mCM.getDataCallList(response); + } + + public boolean getDataRoamingEnabled() { + return mDataConnection.getDataOnRoamingEnabled(); + } + + public List getCurrentDataConnectionList () { + return mDataConnection.getAllDataConnections(); + } + + public void setVoiceMailNumber(String alphaTag, + String voiceMailNumber, + Message onComplete) { + //mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); + //TODO: Where do we have to store this value has to be clarified with QC + } + + public String getVoiceMailNumber() { + //TODO: Where can we get this value has to be clarified with QC + //return mSIMRecords.getVoiceMailNumber(); +// throw new RuntimeException(); + return "12345"; + } + + public String getVoiceMailAlphaTag() { + // TODO: Where can we get this value has to be clarified with QC. + String ret = "";//TODO: Remove = "", if we know where to get this value. + + //ret = mSIMRecords.getVoiceMailAlphaTag(); + + if (ret == null || ret.length() == 0) { + return mContext.getText( + com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); + } + + return ret; + } + + public boolean enableDataConnectivity() { + return mDataConnection.setDataEnabled(true); + } + + public void disableLocationUpdates() { + mSST.disableLocationUpdates(); + } + + public boolean getIccRecordsLoaded() { + return mRuimRecords.getRecordsLoaded(); + } + + public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { + Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA"); + } + + public void setCallForwardingOption(int commandInterfaceCFAction, + int commandInterfaceCFReason, + String dialingNumber, + int timerSeconds, + Message onComplete) { + Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA"); + } + + public void + getOutgoingCallerIdDisplay(Message onComplete) { + Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA"); + } + + public boolean + getCallForwardingIndicator() { + Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA"); + return false; + } + + public void explicitCallTransfer() { + Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA"); + } + + public String getLine1AlphaTag() { + Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA"); + return null; + } + + /** + * Notify any interested party of a Phone state change. + */ + /*package*/ void notifyPhoneStateChanged() { + mNotifier.notifyPhoneState(this); + } + + /** + * Notifies registrants (ie, activities in the Phone app) about + * changes to call state (including Phone and Connection changes). + */ + /*package*/ void notifyCallStateChanged() { + /* we'd love it if this was package-scoped*/ + super.notifyCallStateChangedP(); + } + + void notifyServiceStateChanged(ServiceState ss) { + super.notifyServiceStateChangedP(ss); + } + + void notifyLocationChanged() { + mNotifier.notifyCellLocation(this); + } + + /*package*/ void notifyNewRingingConnection(Connection c) { + /* we'd love it if this was package-scoped*/ + super.notifyNewRingingConnectionP(c); + } + + /** + * Notifiy registrants of a RING event. + */ + void notifyIncomingRing() { + AsyncResult ar = new AsyncResult(null, this, null); + mIncomingRingRegistrants.notifyRegistrants(ar); + } + + /*package*/ void notifyDisconnect(Connection cn) { + mDisconnectRegistrants.notifyResult(cn); + } + + void notifyUnknownConnection() { + mUnknownConnectionRegistrants.notifyResult(this); + } + + /*package*/ void + updateMessageWaitingIndicator(boolean mwi) { + // this also calls notifyMessageWaitingIndicator() + mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); + } + + public void + notifyMessageWaitingIndicator() { + mNotifier.notifyMessageWaitingChanged(this); + } + + /** + * Removes the given FC from the pending list and notifies + * registrants that it is complete. + * @param fc FC that is done + */ + /*package*/ void onFeatureCodeDone(FeatureCode fc) { + /* Only notify complete if it's on the pending list. + * Otherwise, it's already been handled (eg, previously canceled). + * The exception is cancellation of an incoming USSD-REQUEST, which is + * not on the list. + */ + mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); + } + + //***** Inner Classes + class MyHandler extends Handler { + MyHandler() { + } + + MyHandler(Looper l) { + super(l); + } + + public void handleMessage(Message msg) { + AsyncResult ar; + Message onComplete; + + switch(msg.what) { + case EVENT_RADIO_AVAILABLE: { + mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); + + mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); + } + break; + + case EVENT_GET_BASEBAND_VERSION_DONE:{ + ar = (AsyncResult)msg.obj; + + if (ar.exception != null) { + break; + } + + if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result); + setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result); + } + break; + + case EVENT_GET_DEVICE_IDENTITY_DONE:{ + ar = (AsyncResult)msg.obj; + + if (ar.exception != null) { + break; + } + String[] respId = (String[])ar.result; + mEsn = respId[2]; + mMeid = respId[3]; + } + break; + + case EVENT_RUIM_RECORDS_LOADED:{ + Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); + } + break; + + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{ + Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); + } + break; + + case EVENT_RADIO_ON:{ + Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received"); + } + break; + + case EVENT_SSN:{ + Log.d(LOG_TAG, "Event EVENT_SSN Received"); + } + break; + + case EVENT_CALL_RING:{ + Log.d(LOG_TAG, "Event EVENT_CALL_RING Received"); + } + break; + + case EVENT_REGISTERED_TO_NETWORK:{ + Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received"); + } + break; + + case EVENT_NV_READY:{ + Log.d(LOG_TAG, "Event EVENT_NV_READY Received"); + //Inform the Service State Tracker + mNvLoadedRegistrants.notifyRegistrants(); + } + break; + + default:{ + throw new RuntimeException("unexpected event not handled"); + } + } + } + } + + /** + * Retrieves the PhoneSubInfo of the CDMAPhone + */ + public PhoneSubInfo getPhoneSubInfo(){ + return mSubInfo; + } + + /** + * Retrieves the IccSmsInterfaceManager of the CDMAPhone + */ + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return mRuimSmsInterfaceManager; + } + + /** + * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone + */ + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ + return mRuimPhoneBookInterfaceManager; + } + + public void registerForNvLoaded(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mNvLoadedRegistrants.add(r); + } + + public void unregisterForNvLoaded(Handler h) { + mNvLoadedRegistrants.remove(h); + } + + // override for allowing access from other classes of this package + /** + * {@inheritDoc} + */ + public final void setSystemProperty(String property, String value) { + super.setSystemProperty(property, value); + } + + /** + * {@inheritDoc} + */ + public Handler getHandler(){ + return h; + } + + /** + * {@inheritDoc} + */ + public IccFileHandler getIccFileHandler(){ + return this.mIccFileHandler; + } + + /** + * Set the TTY mode of the CDMAPhone + */ + public void setTTYModeEnabled(boolean enable, Message onComplete) { + this.mCM.setTTYModeEnabled(enable, onComplete); +} + + /** + * Queries the TTY mode of the CDMAPhone + */ + public void queryTTYModeEnabled(Message onComplete) { + this.mCM.queryTTYModeEnabled(onComplete); + } + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + public void activateCellBroadcastSms(int activate, Message response) { + mSMS.activateCellBroadcastSms(activate, response); + } + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + public void getCellBroadcastSmsConfig(Message response){ + mSMS.getCellBroadcastSmsConfig(response); + } + + /** + * Configure cdma cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ + mSMS.setCellBroadcastConfig(configValuesArray, response); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java new file mode 100644 index 0000000000000000000000000000000000000000..ea557b2068e1a5f209760f43723e2e575338dcc8 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.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.internal.telephony.cdma; + +/** + * Call fail causes from TS 24.008 . + * These are mostly the cause codes we need to distinguish for the UI. + * See 22.001 Annex F.4 for mapping of cause codes to local tones. + * + * {@hide} + * + */ +public interface CallFailCause { + static final int NORMAL_CLEARING = 16; + // Busy Tone + static final int USER_BUSY = 17; + +// // No Tone +// static final int NUMBER_CHANGED = 22; +// static final int STATUS_ENQUIRY = 30; + static final int NORMAL_UNSPECIFIED = 31; +// +// // Congestion Tone +// static final int NO_CIRCUIT_AVAIL = 34; +// static final int TEMPORARY_FAILURE = 41; +// static final int SWITCHING_CONGESTION = 42; +// static final int CHANNEL_NOT_AVAIL = 44; +// static final int QOS_NOT_AVAIL = 49; +// static final int BEARER_NOT_AVAIL = 58; +// +// // others +// static final int ACM_LIMIT_EXCEEDED = 68; +// static final int CALL_BARRED = 240; +// static final int FDN_BLOCKED = 241; + static final int ERROR_UNSPECIFIED = 0xffff; +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java new file mode 100644 index 0000000000000000000000000000000000000000..34514d9282843d942804a4f96f55559a9548246b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java @@ -0,0 +1,209 @@ +/* + * 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.cdma; + +import java.util.ArrayList; +import java.util.List; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.Phone; + +/** + * {@hide} + */ +public final class CdmaCall extends Call { + /*************************** Instance Variables **************************/ + + /*package*/ ArrayList connections = new ArrayList(); + /*package*/ State state = State.IDLE; + /*package*/ CdmaCallTracker owner; + + /***************************** Class Methods *****************************/ + + static State + stateFromDCState (DriverCall.State dcState) { + switch (dcState) { + case ACTIVE: return State.ACTIVE; + case HOLDING: return State.HOLDING; + case DIALING: return State.DIALING; + case ALERTING: return State.ALERTING; + case INCOMING: return State.INCOMING; + case WAITING: return State.WAITING; + default: throw new RuntimeException ("illegal call state:" + dcState); + } + } + + + /****************************** Constructors *****************************/ + /*package*/ + CdmaCall (CdmaCallTracker owner) { + this.owner = owner; + } + + public void dispose() { + } + + /************************** Overridden from Call *************************/ + public List + getConnections() { + // FIXME should return Collections.unmodifiableList(); + return connections; + } + + public State + getState() { + return state; + } + + public Phone + getPhone() { + //TODO, see GsmCall + return null; + } + + public boolean isMultiparty() { + return connections.size() > 1; + } + + /** Please note: if this is the foreground call and a + * background call exists, the background call will be resumed + * because an AT+CHLD=1 will be sent + */ + public void + hangup() throws CallStateException { + owner.hangup(this); + } + + public String + toString() { + return state.toString(); + } + + //***** Called from CdmaConnection + + /*package*/ void + attach(Connection conn, DriverCall dc) { + connections.add(conn); + + state = stateFromDCState (dc.state); + } + + /*package*/ void + attachFake(Connection conn, State state) { + connections.add(conn); + + this.state = state; + } + + /** + * Called by CdmaConnection when it has disconnected + */ + void + connectionDisconnected(CdmaConnection conn) { + if (state != State.DISCONNECTED) { + /* If only disconnected connections remain, we are disconnected*/ + + boolean hasOnlyDisconnectedConnections = true; + + for (int i = 0, s = connections.size() ; i < s; i ++) { + if (connections.get(i).getState() + != State.DISCONNECTED + ) { + hasOnlyDisconnectedConnections = false; + break; + } + } + + if (hasOnlyDisconnectedConnections) { + state = State.DISCONNECTED; + } + } + } + + + /*package*/ void + detach(CdmaConnection conn) { + connections.remove(conn); + + if (connections.size() == 0) { + state = State.IDLE; + } + } + + /*package*/ boolean + update (CdmaConnection conn, DriverCall dc) { + State newState; + boolean changed = false; + + newState = stateFromDCState(dc.state); + + if (newState != state) { + state = newState; + changed = true; + } + + return changed; + } + + /** + * @return true if there's no space in this call for additional + * connections to be added via "conference" + */ + /*package*/ boolean + isFull() { + return connections.size() == CdmaCallTracker.MAX_CONNECTIONS_PER_CALL; + } + + //***** Called from CdmaCallTracker + + + /** + * Called when this Call is being hung up locally (eg, user pressed "end") + * Note that at this point, the hangup request has been dispatched to the radio + * but no response has yet been received so update() has not yet been called + */ + void + onHangupLocal() { + for (int i = 0, s = connections.size() + ; i < s; i++ + ) { + CdmaConnection cn = (CdmaConnection)connections.get(i); + + cn.onHangupLocal(); + } + } + + /** + * Called when it's time to clean up disconnected Connection objects + */ + void clearDisconnected() { + for (int i = connections.size() - 1 ; i >= 0 ; i--) { + CdmaConnection cn = (CdmaConnection)connections.get(i); + + if (cn.getState() == State.DISCONNECTED) { + connections.remove(i); + } + } + + if (connections.size() == 0) { + state = State.IDLE; + } + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java new file mode 100644 index 0000000000000000000000000000000000000000..a1d362fb600f5c5e7158d3eb589990d81056ad33 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -0,0 +1,860 @@ +/* + * 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.cdma; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; +import android.util.Log; + +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CallTracker; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@hide} + */ +public final class CdmaCallTracker extends CallTracker { + static final String LOG_TAG = "CDMA"; + + private static final boolean REPEAT_POLLING = false; + + private static final boolean DBG_POLL = false; + + //***** Constants + + static final int MAX_CONNECTIONS = 1; // only 1 connection allowed in CDMA + static final int MAX_CONNECTIONS_PER_CALL = 1; // only 1 connection allowed per call + + //***** Instance Variables + + CdmaConnection connections[] = new CdmaConnection[MAX_CONNECTIONS]; + RegistrantList voiceCallEndedRegistrants = new RegistrantList(); + RegistrantList voiceCallStartedRegistrants = new RegistrantList(); + + + // connections dropped durin last poll + ArrayList droppedDuringPoll + = new ArrayList(MAX_CONNECTIONS); + + CdmaCall ringingCall = new CdmaCall(this); + // A call that is ringing or (call) waiting + CdmaCall foregroundCall = new CdmaCall(this); + CdmaCall backgroundCall = new CdmaCall(this); + + CdmaConnection pendingMO; + boolean hangupPendingMO; + + CDMAPhone phone; + + boolean desiredMute = false; // false = mute off + + Phone.State state = Phone.State.IDLE; + + +// boolean needsPoll; + + + + //***** Events + + //***** Constructors + CdmaCallTracker(CDMAPhone phone) { + this.phone = phone; + cm = phone.mCM; + cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); + cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null); + cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); + } + + public void dispose() { + cm.unregisterForCallStateChanged(this); + cm.unregisterForOn(this); + cm.unregisterForNotAvailable(this); + + for(CdmaConnection c : connections) { + try { + if(c != null) hangup(c); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + } + + try { + if(pendingMO != null) hangup(pendingMO); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + + clearDisconnected(); + + } + + protected void finalize() { + Log.d(LOG_TAG, "CdmaCallTracker finalized"); + } + + //***** Instance Methods + + //***** Public Methods + public void registerForVoiceCallStarted(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + voiceCallStartedRegistrants.add(r); + } + public void unregisterForVoiceCallStarted(Handler h) { + voiceCallStartedRegistrants.remove(h); + } + + public void registerForVoiceCallEnded(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + voiceCallEndedRegistrants.add(r); + } + + public void unregisterForVoiceCallEnded(Handler h) { + voiceCallEndedRegistrants.remove(h); + } + + private void + fakeHoldForegroundBeforeDial() { + List connCopy; + + // We need to make a copy here, since fakeHoldBeforeDial() + // modifies the lists, and we don't want to reverse the order + connCopy = (List) foregroundCall.connections.clone(); + + for (int i = 0, s = connCopy.size() ; i < s ; i++) { + CdmaConnection conn = (CdmaConnection)connCopy.get(i); + + conn.fakeHoldBeforeDial(); + } + } + + /** + * clirMode is one of the CLIR_ constants + */ + Connection + dial (String dialString, int clirMode) throws CallStateException { + // note that this triggers call state changed notif + clearDisconnected(); + + if (!canDial()) { + throw new CallStateException("cannot dial in current state"); + } + + // The new call must be assigned to the foreground call. + // That call must be idle, so place anything that's + // there on hold + if (foregroundCall.getState() == CdmaCall.State.ACTIVE) { + // this will probably be done by the radio anyway + // but the dial might fail before this happens + // and we need to make sure the foreground call is clear + // for the newly dialed connection + switchWaitingOrHoldingAndActive(); + + // Fake local state so that + // a) foregroundCall is empty for the newly dialed connection + // b) hasNonHangupStateChanged remains false in the + // next poll, so that we don't clear a failed dialing call + fakeHoldForegroundBeforeDial(); + } + + if (foregroundCall.getState() != CdmaCall.State.IDLE) { + //we should have failed in !canDial() above before we get here + throw new CallStateException("cannot dial in current state"); + } + + pendingMO = new CdmaConnection(phone.getContext(), dialString, this, foregroundCall); + hangupPendingMO = false; + + if (pendingMO.address == null || pendingMO.address.length() == 0 + || pendingMO.address.indexOf(PhoneNumberUtils.WILD) >= 0 + ) { + // Phone number is invalid + pendingMO.cause = Connection.DisconnectCause.INVALID_NUMBER; + + // handlePollCalls() will notice this call not present + // and will mark it as dropped. + pollCallsWhenSafe(); + } else { + // Always unmute when initiating a new call + setMute(false); + + cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); + } + + updatePhoneState(); + phone.notifyCallStateChanged(); + + return pendingMO; + } + + + Connection + dial (String dialString) throws CallStateException { + return dial(dialString, CommandsInterface.CLIR_DEFAULT); + } + + void + acceptCall () throws CallStateException { + // FIXME if SWITCH fails, should retry with ANSWER + // in case the active/holding call disappeared and this + // is no longer call waiting + + if (ringingCall.getState() == CdmaCall.State.INCOMING) { + Log.i("phone", "acceptCall: incoming..."); + // Always unmute when answering a new call + setMute(false); + cm.acceptCall(obtainCompleteMessage()); + } else if (ringingCall.getState() == CdmaCall.State.WAITING) { + setMute(false); + switchWaitingOrHoldingAndActive(); + } else { + throw new CallStateException("phone not ringing"); + } + } + + void + rejectCall () throws CallStateException { + // AT+CHLD=0 means "release held or UDUB" + // so if the phone isn't ringing, this could hang up held + if (ringingCall.getState().isRinging()) { + cm.rejectCall(obtainCompleteMessage()); + } else { + throw new CallStateException("phone not ringing"); + } + } + + void + switchWaitingOrHoldingAndActive() throws CallStateException { + // Should we bother with this check? + if (ringingCall.getState() == CdmaCall.State.INCOMING) { + throw new CallStateException("cannot be in the incoming state"); + } else { + cm.sendCDMAFeatureCode("", obtainCompleteMessage(EVENT_SWITCH_RESULT)); + } + } + + void + conference() throws CallStateException { + // three way calls in CDMA will be handled by feature codes + Log.e(LOG_TAG, "conference: not possible in CDMA"); + } + + void + explicitCallTransfer() throws CallStateException { + cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT)); + } + + void + clearDisconnected() { + internalClearDisconnected(); + + updatePhoneState(); + phone.notifyCallStateChanged(); + } + + boolean + canConference() { + return foregroundCall.getState() == CdmaCall.State.ACTIVE + && backgroundCall.getState() == CdmaCall.State.HOLDING + && !backgroundCall.isFull() + && !foregroundCall.isFull(); + } + + boolean + canDial() { + boolean ret; + int serviceState = phone.getServiceState().getState(); + + ret = (serviceState != ServiceState.STATE_POWER_OFF) && + pendingMO == null + && !ringingCall.isRinging() + && (!foregroundCall.getState().isAlive() + || !backgroundCall.getState().isAlive()); + + return ret; + } + + boolean + canTransfer() { + Log.e(LOG_TAG, "canTransfer: not possible in CDMA"); + return false; + } + + //***** Private Instance Methods + + private void + internalClearDisconnected() { + ringingCall.clearDisconnected(); + foregroundCall.clearDisconnected(); + backgroundCall.clearDisconnected(); + } + + /** + * Obtain a message to use for signalling "invoke getCurrentCalls() when + * this operation and all other pending operations are complete + */ + private Message + obtainCompleteMessage() { + return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); + } + + /** + * Obtain a message to use for signalling "invoke getCurrentCalls() when + * this operation and all other pending operations are complete + */ + private Message + obtainCompleteMessage(int what) { + pendingOperations++; + lastRelevantPoll = null; + needsPoll = true; + + if (DBG_POLL) log("obtainCompleteMessage: pendingOperations=" + + pendingOperations + ", needsPoll=" + needsPoll); + + return obtainMessage(what); + } + + private void + operationComplete() { + pendingOperations--; + + if (DBG_POLL) log("operationComplete: pendingOperations=" + + pendingOperations + ", needsPoll=" + needsPoll); + + if (pendingOperations == 0 && needsPoll) { + lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); + cm.getCurrentCalls(lastRelevantPoll); + } else if (pendingOperations < 0) { + // this should never happen + Log.e(LOG_TAG,"CdmaCallTracker.pendingOperations < 0"); + pendingOperations = 0; + } + } + + + + private void + updatePhoneState() { + Phone.State oldState = state; + + if (ringingCall.isRinging()) { + state = Phone.State.RINGING; + } else if (pendingMO != null || + !(foregroundCall.isIdle() && backgroundCall.isIdle())) { + state = Phone.State.OFFHOOK; + } else { + state = Phone.State.IDLE; + } + + if (state == Phone.State.IDLE && oldState != state) { + voiceCallEndedRegistrants.notifyRegistrants( + new AsyncResult(null, null, null)); + } else if (oldState == Phone.State.IDLE && oldState != state) { + voiceCallStartedRegistrants.notifyRegistrants ( + new AsyncResult(null, null, null)); + } + + if (state != oldState) { + phone.notifyPhoneStateChanged(); + } + } + + // ***** Overwritten from CallTracker + + protected void + handlePollCalls(AsyncResult ar) { + List polledCalls; + + if (ar.exception == null) { + polledCalls = (List)ar.result; + } else if (isCommandExceptionRadioNotAvailable(ar.exception)) { + // just a dummy empty ArrayList to cause the loop + // to hang up all the calls + polledCalls = new ArrayList(); + } else { + // Radio probably wasn't ready--try again in a bit + // But don't keep polling if the channel is closed + pollCallsAfterDelay(); + return; + } + + Connection newRinging = null; //or waiting + boolean hasNonHangupStateChanged = false; // Any change besides + // a dropped connection + boolean needsPollDelay = false; + boolean unknownConnectionAppeared = false; + + for (int i = 0, curDC = 0, dcSize = polledCalls.size() + ; i < connections.length; i++) { + CdmaConnection conn = connections[i]; + DriverCall dc = null; + + // polledCall list is sparse + if (curDC < dcSize) { + dc = (DriverCall) polledCalls.get(curDC); + + if (dc.index == i+1) { + curDC++; + } else { + dc = null; + } + } + + if (DBG_POLL) log("poll: conn[i=" + i + "]=" + + conn+", dc=" + dc); + + if (conn == null && dc != null) { + // Connection appeared in CLCC response that we don't know about + if (pendingMO != null && pendingMO.compareTo(dc)) { + + if (DBG_POLL) log("poll: pendingMO=" + pendingMO); + + // It's our pending mobile originating call + connections[i] = pendingMO; + pendingMO.index = i; + pendingMO.update(dc); + pendingMO = null; + + // Someone has already asked to hangup this call + if (hangupPendingMO) { + hangupPendingMO = false; + try { + if (Phone.DEBUG_PHONE) log( + "poll: hangupPendingMO, hangup conn " + i); + hangup(connections[i]); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup"); + } + + // Do not continue processing this poll + // Wait for hangup and repoll + return; + } + } else { + connections[i] = new CdmaConnection(phone.getContext(), dc, this, i); + + // it's a ringing call + if (connections[i].getCall() == ringingCall) { + newRinging = connections[i]; + } else { + // Something strange happened: a call appeared + // which is neither a ringing call or one we created. + // Either we've crashed and re-attached to an existing + // call, or something else (eg, SIM) initiated the call. + + Log.i(LOG_TAG,"Phantom call appeared " + dc); + + // If it's a connected call, set the connect time so that + // it's non-zero. It may not be accurate, but at least + // it won't appear as a Missed Call. + if (dc.state != DriverCall.State.ALERTING + && dc.state != DriverCall.State.DIALING) { + connections[i].connectTime = System.currentTimeMillis(); + } + + unknownConnectionAppeared = true; + } + } + hasNonHangupStateChanged = true; + } else if (conn != null && dc == null) { + // Connection missing in CLCC response that we were + // tracking. + droppedDuringPoll.add(conn); + // Dropped connections are removed from the CallTracker + // list but kept in the Call list + connections[i] = null; + } else if (conn != null && dc != null && !conn.compareTo(dc)) { + // Connection in CLCC response does not match what + // we were tracking. Assume dropped call and new call + + droppedDuringPoll.add(conn); + connections[i] = new CdmaConnection (phone.getContext(), dc, this, i); + + if (connections[i].getCall() == ringingCall) { + newRinging = connections[i]; + } // else something strange happened + hasNonHangupStateChanged = true; + } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */ + boolean changed; + changed = conn.update(dc); + hasNonHangupStateChanged = hasNonHangupStateChanged || changed; + } + + if (REPEAT_POLLING) { + if (dc != null) { + // FIXME with RIL, we should not need this anymore + if ((dc.state == DriverCall.State.DIALING + /*&& cm.getOption(cm.OPTION_POLL_DIALING)*/) + || (dc.state == DriverCall.State.ALERTING + /*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/) + || (dc.state == DriverCall.State.INCOMING + /*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/) + || (dc.state == DriverCall.State.WAITING + /*&& cm.getOption(cm.OPTION_POLL_WAITING)*/) + ) { + // Sometimes there's no unsolicited notification + // for state transitions + needsPollDelay = true; + } + } + } + } + + // This is the first poll after an ATD. + // We expect the pending call to appear in the list + // If it does not, we land here + if (pendingMO != null) { + Log.d(LOG_TAG,"Pending MO dropped before poll fg state:" + + foregroundCall.getState()); + + droppedDuringPoll.add(pendingMO); + pendingMO = null; + hangupPendingMO = false; + } + + if (newRinging != null) { + phone.notifyNewRingingConnection(newRinging); + } + + // clear the "local hangup" and "missed/rejected call" + // cases from the "dropped during poll" list + // These cases need no "last call fail" reason + for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) { + CdmaConnection conn = droppedDuringPoll.get(i); + + if (conn.isIncoming() && conn.getConnectTime() == 0) { + // Missed or rejected call + Connection.DisconnectCause cause; + if (conn.cause == Connection.DisconnectCause.LOCAL) { + cause = Connection.DisconnectCause.INCOMING_REJECTED; + } else { + cause = Connection.DisconnectCause.INCOMING_MISSED; + } + + if (Phone.DEBUG_PHONE) { + log("missed/rejected call, conn.cause=" + conn.cause); + log("setting cause to " + cause); + } + droppedDuringPoll.remove(i); + conn.onDisconnect(cause); + } else if (conn.cause == Connection.DisconnectCause.LOCAL) { + // Local hangup + droppedDuringPoll.remove(i); + conn.onDisconnect(Connection.DisconnectCause.LOCAL); + } else if (conn.cause == Connection.DisconnectCause.INVALID_NUMBER) { + droppedDuringPoll.remove(i); + conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER); + } + } + + // Any non-local disconnects: determine cause + if (droppedDuringPoll.size() > 0) { + cm.getLastCallFailCause( + obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE)); + } + + if (needsPollDelay) { + pollCallsAfterDelay(); + } + + // Cases when we can no longer keep disconnected Connection's + // with their previous calls + // 1) the phone has started to ring + // 2) A Call/Connection object has changed state... + // we may have switched or held or answered (but not hung up) + if (newRinging != null || hasNonHangupStateChanged) { + internalClearDisconnected(); + } + + updatePhoneState(); + + if (unknownConnectionAppeared) { + phone.notifyUnknownConnection(); + } + + if (hasNonHangupStateChanged || newRinging != null) { + phone.notifyCallStateChanged(); + } + + //dumpState(); + } + + //***** Called from CdmaConnection + /*package*/ void + hangup (CdmaConnection conn) throws CallStateException { + if (conn.owner != this) { + throw new CallStateException ("CdmaConnection " + conn + + "does not belong to CdmaCallTracker " + this); + } + + if (conn == pendingMO) { + // We're hanging up an outgoing call that doesn't have it's + // GSM index assigned yet + + if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true"); + hangupPendingMO = true; + } else { + try { + cm.hangupConnection (conn.getCDMAIndex(), obtainCompleteMessage()); + } catch (CallStateException ex) { + // Ignore "connection not found" + // Call may have hung up already + Log.w(LOG_TAG,"CdmaCallTracker WARN: hangup() on absent connection " + + conn); + } + } + + conn.onHangupLocal(); + } + + /*package*/ void + separate (CdmaConnection conn) throws CallStateException { + if (conn.owner != this) { + throw new CallStateException ("CdmaConnection " + conn + + "does not belong to CdmaCallTracker " + this); + } + try { + cm.separateConnection (conn.getCDMAIndex(), + obtainCompleteMessage(EVENT_SEPARATE_RESULT)); + } catch (CallStateException ex) { + // Ignore "connection not found" + // Call may have hung up already + Log.w(LOG_TAG,"CdmaCallTracker WARN: separate() on absent connection " + + conn); + } + } + + //***** Called from CDMAPhone + + /*package*/ void + setMute(boolean mute) { + desiredMute = mute; + cm.setMute(desiredMute, null); + } + + /*package*/ boolean + getMute() { + return desiredMute; + } + + + //***** Called from CdmaCall + + /* package */ void + hangup (CdmaCall call) throws CallStateException { + if (call.getConnections().size() == 0) { + throw new CallStateException("no connections in call"); + } + + if (call == ringingCall) { + if (Phone.DEBUG_PHONE) log("(ringing) hangup waiting or background"); + cm.hangupWaitingOrBackground(obtainCompleteMessage()); + } else if (call == foregroundCall) { + if (call.isDialingOrAlerting()) { + if (Phone.DEBUG_PHONE) { + log("(foregnd) hangup dialing or alerting..."); + } + hangup((CdmaConnection)(call.getConnections().get(0))); + } else { + hangupForegroundResumeBackground(); + } + } else if (call == backgroundCall) { + if (ringingCall.isRinging()) { + if (Phone.DEBUG_PHONE) { + log("hangup all conns in background call"); + } + hangupAllConnections(call); + } else { + hangupWaitingOrBackground(); + } + } else { + throw new RuntimeException ("CdmaCall " + call + + "does not belong to CdmaCallTracker " + this); + } + + call.onHangupLocal(); + } + + /* package */ + void hangupWaitingOrBackground() { + if (Phone.DEBUG_PHONE) log("hangupWaitingOrBackground"); + cm.hangupWaitingOrBackground(obtainCompleteMessage()); + } + + /* package */ + void hangupForegroundResumeBackground() { + if (Phone.DEBUG_PHONE) log("hangupForegroundResumeBackground"); + cm.hangupForegroundResumeBackground(obtainCompleteMessage()); + } + + void hangupConnectionByIndex(CdmaCall call, int index) + throws CallStateException { + int count = call.connections.size(); + for (int i = 0; i < count; i++) { + CdmaConnection cn = (CdmaConnection)call.connections.get(i); + if (cn.getCDMAIndex() == index) { + cm.hangupConnection(index, obtainCompleteMessage()); + return; + } + } + + throw new CallStateException("no gsm index found"); + } + + void hangupAllConnections(CdmaCall call) throws CallStateException{ + try { + int count = call.connections.size(); + for (int i = 0; i < count; i++) { + CdmaConnection cn = (CdmaConnection)call.connections.get(i); + cm.hangupConnection(cn.getCDMAIndex(), obtainCompleteMessage()); + } + } catch (CallStateException ex) { + Log.e(LOG_TAG, "hangupConnectionByIndex caught " + ex); + } + } + + /* package */ + CdmaConnection getConnectionByIndex(CdmaCall call, int index) + throws CallStateException { + int count = call.connections.size(); + for (int i = 0; i < count; i++) { + CdmaConnection cn = (CdmaConnection)call.connections.get(i); + if (cn.getCDMAIndex() == index) { + return cn; + } + } + + return null; + } + + private Phone.SuppService getFailedService(int what) { + switch (what) { + case EVENT_SWITCH_RESULT: + return Phone.SuppService.SWITCH; + case EVENT_CONFERENCE_RESULT: + return Phone.SuppService.CONFERENCE; + case EVENT_SEPARATE_RESULT: + return Phone.SuppService.SEPARATE; + case EVENT_ECT_RESULT: + return Phone.SuppService.TRANSFER; + } + return Phone.SuppService.UNKNOWN; + } + + private void handleRadioNotAvailable() { + // handlePollCalls will clear out its + // call list when it gets the CommandException + // error result from this + pollCallsWhenSafe(); + } + + //****** Overridden from Handler + + public void + handleMessage (Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_POLL_CALLS_RESULT:{ + Log.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received"); + ar = (AsyncResult)msg.obj; + + if(msg == lastRelevantPoll) { + if(DBG_POLL) log( + "handle EVENT_POLL_CALL_RESULT: set needsPoll=F"); + needsPoll = false; + lastRelevantPoll = null; + handlePollCalls((AsyncResult)msg.obj); + } + } + break; + + case EVENT_OPERATION_COMPLETE: + ar = (AsyncResult)msg.obj; + operationComplete(); + break; + + case EVENT_SWITCH_RESULT: + ar = (AsyncResult)msg.obj; + operationComplete(); + break; + + case EVENT_GET_LAST_CALL_FAIL_CAUSE: + int causeCode; + ar = (AsyncResult)msg.obj; + + operationComplete(); + + if (ar.exception != null) { + // An exception occurred...just treat the disconnect + // cause as "normal" + causeCode = CallFailCause.NORMAL_CLEARING; + Log.i(LOG_TAG, + "Exception during getLastCallFailCause, assuming normal disconnect"); + } else { + causeCode = ((int[])ar.result)[0]; + } + + for (int i = 0, s = droppedDuringPoll.size() + ; i < s ; i++ + ) { + CdmaConnection conn = droppedDuringPoll.get(i); + + conn.onRemoteDisconnect(causeCode); + } + + updatePhoneState(); + + phone.notifyCallStateChanged(); + droppedDuringPoll.clear(); + break; + + case EVENT_CALL_STATE_CHANGE: + pollCallsWhenSafe(); + break; + + case EVENT_RADIO_AVAILABLE: + handleRadioAvailable(); + break; + + case EVENT_RADIO_NOT_AVAILABLE: + handleRadioNotAvailable(); + break; + + default:{ + throw new RuntimeException("unexpected event not handled"); + } + } + } + + protected void log(String msg) { + Log.d(LOG_TAG, "[CdmaCallTracker] " + msg); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..cdad4a75d6eae743746cf64c21a74ee35313dd74 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java @@ -0,0 +1,705 @@ +/* + * 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.cdma; + +import com.android.internal.telephony.*; +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.Registrant; +import android.os.SystemClock; +import android.util.Config; +import android.util.Log; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; + + +/** + * {@hide} + */ +public class CdmaConnection extends Connection { + static final String LOG_TAG = "CDMA"; + + //***** Instance Variables + + CdmaCallTracker owner; + CdmaCall parent; + + + String address; // MAY BE NULL!!! + String dialString; // outgoing calls only + String postDialString; // outgoing calls only + boolean isIncoming; + boolean disconnected; + + int index; // index in CdmaCallTracker.connections[], -1 if unassigned + + /* + * These time/timespan values are based on System.currentTimeMillis(), + * i.e., "wall clock" time. + */ + long createTime; + long connectTime; + long disconnectTime; + + /* + * These time/timespan values are based on SystemClock.elapsedRealTime(), + * i.e., time since boot. They are appropriate for comparison and + * calculating deltas. + */ + long connectTimeReal; + long duration; + long holdingStartTime; // The time when the Connection last transitioned + // into HOLDING + + int nextPostDialChar; // index into postDialString + + DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED; + PostDialState postDialState = PostDialState.NOT_STARTED; + int numberPresentation = Connection.PRESENTATION_ALLOWED; + + Handler h; + + private PowerManager.WakeLock mPartialWakeLock; + + //***** Event Constants + static final int EVENT_DTMF_DONE = 1; + static final int EVENT_PAUSE_DONE = 2; + static final int EVENT_NEXT_POST_DIAL = 3; + static final int EVENT_WAKE_LOCK_TIMEOUT = 4; + + //***** Constants + static final int PAUSE_DELAY_FIRST_MILLIS = 100; + static final int PAUSE_DELAY_MILLIS = 3 * 1000; + static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000; + + //***** Inner Classes + + class MyHandler extends Handler { + MyHandler(Looper l) {super(l);} + + public void + handleMessage(Message msg) { + + switch (msg.what) { + case EVENT_NEXT_POST_DIAL: + case EVENT_DTMF_DONE: + case EVENT_PAUSE_DONE: + processNextPostDialChar(); + break; + case EVENT_WAKE_LOCK_TIMEOUT: + releaseWakeLock(); + break; + } + } + } + + //***** Constructors + + /** This is probably an MT call that we first saw in a CLCC response */ + /*package*/ + CdmaConnection (Context context, DriverCall dc, CdmaCallTracker ct, int index) { + createWakeLock(context); + acquireWakeLock(); + + owner = ct; + h = new MyHandler(owner.getLooper()); + + address = dc.number; + + isIncoming = dc.isMT; + createTime = System.currentTimeMillis(); + numberPresentation = dc.numberPresentation; + + this.index = index; + + parent = parentFromDCState (dc.state); + parent.attach(this, dc); + } + + /** This is an MO call, created when dialing */ + /*package*/ + CdmaConnection (Context context, String dialString, CdmaCallTracker ct, CdmaCall parent) { + createWakeLock(context); + acquireWakeLock(); + + owner = ct; + h = new MyHandler(owner.getLooper()); + + this.dialString = dialString; + + this.address = PhoneNumberUtils.extractNetworkPortion(dialString); + this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString); + + index = -1; + + isIncoming = false; + createTime = System.currentTimeMillis(); + + this.parent = parent; + parent.attachFake(this, CdmaCall.State.DIALING); + } + + public void dispose() { + } + + static boolean + equalsHandlesNulls (Object a, Object b) { + return (a == null) ? (b == null) : a.equals (b); + } + + /*package*/ boolean + compareTo(DriverCall c) { + // On mobile originated (MO) calls, the phone number may have changed + // due to a SIM Toolkit call control modification. + // + // We assume we know when MO calls are created (since we created them) + // and therefore don't need to compare the phone number anyway. + if (! (isIncoming || c.isMT)) return true; + + // ... but we can compare phone numbers on MT calls, and we have + // no control over when they begin, so we might as well + + String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); + return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); + } + + public String + toString() { + return (isIncoming ? "incoming" : "outgoing"); + } + + public String getAddress() { + return address; + } + + public CdmaCall getCall() { + return parent; + } + + public long getCreateTime() { + return createTime; + } + + public long getConnectTime() { + return connectTime; + } + + public long getDisconnectTime() { + return disconnectTime; + } + + public long getDurationMillis() { + if (connectTimeReal == 0) { + return 0; + } else if (duration == 0) { + return SystemClock.elapsedRealtime() - connectTimeReal; + } else { + return duration; + } + } + + public long getHoldDurationMillis() { + if (getState() != CdmaCall.State.HOLDING) { + // If not holding, return 0 + return 0; + } else { + return SystemClock.elapsedRealtime() - holdingStartTime; + } + } + + public DisconnectCause getDisconnectCause() { + return cause; + } + + public boolean isIncoming() { + return isIncoming; + } + + public CdmaCall.State getState() { + if (disconnected) { + return CdmaCall.State.DISCONNECTED; + } else { + return super.getState(); + } + } + + public void hangup() throws CallStateException { + if (!disconnected) { + owner.hangup(this); + } else { + throw new CallStateException ("disconnected"); + } + } + + public void separate() throws CallStateException { + if (!disconnected) { + owner.separate(this); + } else { + throw new CallStateException ("disconnected"); + } + } + + public PostDialState getPostDialState() { + return postDialState; + } + + public void proceedAfterWaitChar() { + if (postDialState != PostDialState.WAIT) { + Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + + "getPostDialState() to be WAIT but was " + postDialState); + return; + } + + setPostDialState(PostDialState.STARTED); + + processNextPostDialChar(); + } + + public void proceedAfterWildChar(String str) { + if (postDialState != PostDialState.WILD) { + Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + + "getPostDialState() to be WILD but was " + postDialState); + return; + } + + setPostDialState(PostDialState.STARTED); + + if (false) { + boolean playedTone = false; + int len = (str != null ? str.length() : 0); + + for (int i=0; i"); + } + + /** + * Setup a data connection + * + * @param onCompleted + * notify success or not after down + */ + void connect(Message onCompleted) { + if (DBG) log("CdmaDataConnection Connecting..."); + + state = State.ACTIVATING; + onConnectCompleted = onCompleted; + createTime = -1; + lastFailTime = -1; + lastFailCause = FailCause.NONE; + receivedDisconnectReq = false; + phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE), null, null, null, + null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); + } + + protected void disconnect(Message msg) { + onDisconnect = msg; + if (state == State.ACTIVE) { + if (phone.mCM.getRadioState().isOn()) { + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); + } + } else if (state == State.ACTIVATING) { + receivedDisconnectReq = true; + } else { + // state == INACTIVE. Nothing to do, so notify immediately. + notifyDisconnect(msg); + } + } + + + public String toString() { + return "State=" + state + " create=" + createTime + " lastFail=" + + lastFailTime + " lastFailCause=" + lastFailCause; + } + + + protected void notifyFail(FailCause cause, Message onCompleted) { + if (onCompleted == null) { + return; + } + state = State.INACTIVE; + lastFailCause = cause; + lastFailTime = System.currentTimeMillis(); + onConnectCompleted = null; + + if(DBG) { + log("Notify data connection fail at " + lastFailTime + + " due to " + lastFailCause); + } + + AsyncResult.forMessage(onCompleted, cause, new Exception()); + onCompleted.sendToTarget(); + } + + protected void notifySuccess(Message onCompleted) { + if (onCompleted == null) { + return; + } + + state = State.ACTIVE; + createTime = System.currentTimeMillis(); + onConnectCompleted = null; + onCompleted.arg1 = cid; + + if (DBG) log("Notify data connection success at " + createTime); + + AsyncResult.forMessage(onCompleted); + onCompleted.sendToTarget(); + } + + protected void notifyDisconnect(Message msg) { + if (DBG) log("Notify data connection disconnect"); + + if (msg != null) { + AsyncResult.forMessage(msg); + msg.sendToTarget(); + } + clearSettings(); + } + + protected void onLinkStateChanged(DataLink.LinkState linkState) { + switch (linkState) { + case LINK_UP: + notifySuccess(onConnectCompleted); + break; + + case LINK_DOWN: + case LINK_EXITED: + phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + break; + } + } + + protected FailCause getFailCauseFromRequest(int rilCause) { + FailCause cause; + + switch (rilCause) { + case PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING: + cause = FailCause.BARRED; + break; + case PS_NET_DOWN_REASON_AUTH_FAILED: + cause = FailCause.USER_AUTHENTICATION; + break; + case PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED: + cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; + break; + case PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED: + cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; + break; + default: + cause = FailCause.UNKNOWN; + } + return cause; + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaDataConnection] " + s); + } + + @Override + protected void onDeactivated(AsyncResult ar) { + notifyDisconnect((Message) ar.userObj); + if (DBG) log("CDMA Connection Deactivated"); + } + + @Override + protected void onSetupConnectionCompleted(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception); + + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + if (ar.exception instanceof CommandException + && ((CommandException) (ar.exception)).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE) { + notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted); + } else { + phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + } + } + } else { + if (receivedDisconnectReq) { + // Don't bother reporting success if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + disconnect(onDisconnect); + } else { + String[] response = ((String[]) ar.result); + cid = Integer.parseInt(response[0]); + + if (response.length > 2) { + interfaceName = response[1]; + ipAddress = response[2]; + String prefix = "net." + interfaceName + "."; + gatewayAddress = SystemProperties.get(prefix + "gw"); + dnsServers[0] = SystemProperties.get(prefix + "dns1"); + dnsServers[1] = SystemProperties.get(prefix + "dns2"); + if (DBG) { + log("interface=" + interfaceName + " ipAddress=" + ipAddress + + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] + + " DNS2=" + dnsServers[1]); + } + + if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) + && !((CDMAPhone) phone).isDnsCheckDisabled()) { + // Work around a race condition where QMI does not fill in DNS: + // Deactivate PDP and let DataConnectionTracker retry. + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, + dnsServers[0]); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); + return; + } + } + + onLinkStateChanged(DataLink.LinkState.LINK_UP); + + if (DBG) log("CdmaDataConnection setup on cid = " + cid); + } + } + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java new file mode 100644 index 0000000000000000000000000000000000000000..651c5051f495632193fd6ca29ec493f352dd4ddb --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -0,0 +1,932 @@ +/* + * 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.cdma; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.NetworkInfo; +import android.net.wifi.WifiManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.INetStatService; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.preference.PreferenceManager; +import android.provider.Checkin; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.util.EventLog; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataConnection.FailCause; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.TelephonyEventLog; + +import java.util.ArrayList; + +/** + * WINK:TODO: In GsmDataConnectionTracker there are + * EventLog's used quite a few places maybe + * more need to be added in this file? + * + * {@hide} + */ +public final class CdmaDataConnectionTracker extends DataConnectionTracker { + private static final String LOG_TAG = "CDMA"; + private static final boolean DBG = true; + + private CDMAPhone mCdmaPhone; + + // Indicates baseband will not auto-attach + private boolean noAutoAttach = false; + long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + private boolean mIsScreenOn = true; + + //useful for debugging + boolean failNextConnect = false; + + /** + * dataConnectionList holds all the Data connection + */ + private ArrayList dataConnectionList; + + /** Currently active CdmaDataConnection */ + private CdmaDataConnection mActiveDataConnection; + + /** Defined cdma connection profiles */ + private static final int EXTERNAL_NETWORK_DEFAULT_ID = 0; + private static final int EXTERNAL_NETWORK_NUM_TYPES = 1; + + private boolean[] dataEnabled = new boolean[EXTERNAL_NETWORK_NUM_TYPES]; + + /** + * Pool size of CdmaDataConnection objects. + */ + private static final int DATA_CONNECTION_POOL_SIZE = 1; + + private static final int POLL_CONNECTION_MILLIS = 5 * 1000; + private static final String INTENT_RECONNECT_ALARM = + "com.android.internal.telephony.cdma-reconnect"; + private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; + + // Possibly promoate to base class, the only difference is + // the INTENT_RECONNECT_ALARM action is a different string. + // Do consider technology changes if it is promoted. + BroadcastReceiver mIntentReceiver = new BroadcastReceiver () + { + @Override + public void onReceive(Context context, Intent intent) + { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_SCREEN_ON)) { + mIsScreenOn = true; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + mIsScreenOn = false; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals((INTENT_RECONNECT_ALARM))) { + Log.d(LOG_TAG, "Data reconnect alarm. Previous state was " + state); + + 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; + } + } + } + }; + + + //***** Constructor + + CdmaDataConnectionTracker(CDMAPhone p) { + super(p); + mCdmaPhone = p; + + p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mRuimRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); + p.mCM.registerForNVReady(this, EVENT_NV_READY, null); + p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null); + p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); + p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); + p.mSST.registerForCdmaDataConnectionAttached(this, EVENT_TRY_SETUP_DATA, null); + p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null); + p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); + p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + + this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); + + IntentFilter filter = new IntentFilter(); + filter.addAction(INTENT_RECONNECT_ALARM); + 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); + + p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h); + + mDataConnectionTracker = this; + + createAllDataConnectionList(); + + // This preference tells us 1) initial condition for "dataEnabled", + // and 2) whether the RIL will setup the baseband to auto-PS attach. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); + + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] = + !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false); + noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + } + + public void dispose() { + //Unregister from all events + phone.mCM.unregisterForAvailable(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this); + phone.mCM.unregisterForNVReady(this); + phone.mCM.unregisterForDataStateChanged(this); + mCdmaPhone.mCT.unregisterForVoiceCallEnded(this); + mCdmaPhone.mCT.unregisterForVoiceCallStarted(this); + mCdmaPhone.mSST.unregisterForCdmaDataConnectionAttached(this); + mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this); + mCdmaPhone.mSST.unregisterForRoamingOn(this); + mCdmaPhone.mSST.unregisterForRoamingOff(this); + + phone.getContext().unregisterReceiver(this.mIntentReceiver); + destroyAllDataConnectionList(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized"); + } + + void setState(State s) { + if (DBG) log ("setState: " + s); + if (state != s) { + if (s == State.INITING) { // request Data connection context + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_DATA_ATTEMPTED, 1, 0.0); + } + + if (s == State.CONNECTED) { // pppd is up + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_DATA_CONNECTED, 1, 0.0); + } + } + + state = s; + } + + public int enableApnType(String type) { + // This request is mainly used to enable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to enableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_ALREADY_ACTIVE; + } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { + Log.w(LOG_TAG, "Phone.APN_TYPE_SUPL not enabled for CDMA"); + return Phone.APN_REQUEST_FAILED; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + public int disableApnType(String type) { + // This request is mainly used to disable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to disableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_REQUEST_STARTED; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + private boolean isEnabled(int cdmaDataProfile) { + return dataEnabled[cdmaDataProfile]; + } + + private void setEnabled(int cdmaDataProfile, boolean enable) { + Log.d(LOG_TAG, "setEnabled(" + cdmaDataProfile + ", " + enable + ')'); + dataEnabled[cdmaDataProfile] = enable; + Log.d(LOG_TAG, "dataEnabled[DEFAULT_PROFILE]=" + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]); + } + + /** + * Simply tear down data connections due to radio off + * and don't setup again. + */ + public void cleanConnectionBeforeRadioOff() { + cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); + } + + /** + * The data connection is expected to be setup while device + * 1. has ruim card or non-volatile data store + * 2. registered to data connection 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. + */ + public boolean isDataConnectionAsDesired() { + boolean roaming = phone.getServiceState().getRoaming(); + + if (((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || + mCdmaPhone.mRuimRecords.getRecordsLoaded()) && + (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() == + ServiceState.STATE_IN_SERVICE) && + (!roaming || getDataOnRoamingEnabled()) && + !mIsWifiConnected ) { + return (state == State.CONNECTED); + } + return true; + } + + /** + * Prevent mobile data connections from being established, + * or once again allow mobile data connections. If the state + * toggles, then either tear down or set up data, as + * appropriate to match the new state. + *

          This operation only affects the default connection + * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data + * @return {@code true} if the operation succeeded + */ + public boolean setDataEnabled(boolean enable) { + + boolean isEnabled = isEnabled(EXTERNAL_NETWORK_DEFAULT_ID); + + Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled); + if (!isEnabled && enable) { + setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true); + return trySetupData(Phone.REASON_DATA_ENABLED); + } else if (!enable) { + setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false); + cleanUpConnection(true, Phone.REASON_DATA_DISABLED); + return true; + } else // isEnabled && enable + + return true; + } + + /** + * Report the current state of data connectivity (enabled or disabled) + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public boolean getDataEnabled() { + return dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + } + + /** + * Report on whether data connectivity is enabled + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public boolean getAnyDataEnabled() { + for (int i=0; i < EXTERNAL_NETWORK_NUM_TYPES; i++) { + if (isEnabled(i)) return true; + } + return false; + } + + private boolean isDataAllowed() { + boolean roaming = phone.getServiceState().getRoaming(); + return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled()); + } + + private boolean trySetupData(String reason) { + if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); + + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(reason); + + Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); + return true; + } + + int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState(); + boolean roaming = phone.getServiceState().getRoaming(); + + if ((state == State.IDLE || state == State.SCANNING) + && (psState == ServiceState.RADIO_TECHNOLOGY_1xRTT || + psState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 || + psState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || + mCdmaPhone.mRuimRecords.getRecordsLoaded()) + && (mCdmaPhone.mSST.isConcurrentVoiceAndData() || + phone.getState() == Phone.State.IDLE ) + && isDataAllowed()) { + + return setupData(reason); + + } else { + if (DBG) { + log("trySetupData: Not ready for data: " + + " dataState=" + state + + " PS state=" + psState + + " radio state=" + phone.mCM.getRadioState() + + " ruim=" + mCdmaPhone.mRuimRecords.getRecordsLoaded() + + " concurrentVoice&Data=" + mCdmaPhone.mSST.isConcurrentVoiceAndData() + + " phoneState=" + phone.getState() + + " dataEnabled=" + getAnyDataEnabled() + + " roaming=" + roaming + + " dataOnRoamingEnable=" + getDataOnRoamingEnabled()); + } + return false; + } + } + + /** + * If tearDown is true, this only tears down a CONNECTED session. Presently, + * there is no mechanism for abandoning an INITING/CONNECTING session, + * but would likely involve cancelling pending async requests or + * setting a flag or new state to ignore them when they came in + * @param tearDown true if the underlying DataConnection should be + * disconnected. + * @param reason reason for the clean up. + */ + 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 (DataConnection connBase : dataConnectionList) { + CdmaDataConnection conn = (CdmaDataConnection) connBase; + + if(conn != null) { + if (tearDown) { + Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); + conn.disconnect(msg); + } else { + conn.clearSettings(); + } + } + } + + stopNetStatPoll(); + + /* + * 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 conn.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); + } else if (state != State.IDLE) { + setState(State.DISCONNECTING); + } + } + + private CdmaDataConnection findFreeDataConnection() { + for (DataConnection connBase : dataConnectionList) { + CdmaDataConnection conn = (CdmaDataConnection) connBase; + if (conn.getState() == DataConnection.State.INACTIVE) { + return conn; + } + } + return null; + } + + private boolean setupData(String reason) { + + CdmaDataConnection conn = findFreeDataConnection(); + + if (conn == null) { + if (DBG) log("setupData: No free CdmaDataConnectionfound!"); + return false; + } + + mActiveDataConnection = conn; + + Message msg = obtainMessage(); + msg.what = EVENT_DATA_SETUP_COMPLETE; + msg.obj = reason; + conn.connect(msg); + + setState(State.INITING); + phone.notifyDataConnection(reason); + return true; + } + + private void notifyDefaultData(String reason) { + setState(State.CONNECTED); + phone.notifyDataConnection(reason); + startNetStatPoll(); + // reset reconnect timer + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } + + private void resetPollStats() { + txPkts = -1; + rxPkts = -1; + sentSinceLastRecv = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; + mNoRecvPollCount = 0; + } + + protected void startNetStatPoll() { + if (state == State.CONNECTED && netStatPollEnabled == false) { + Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); + resetPollStats(); + netStatPollEnabled = true; + mPollNetStat.run(); + } + } + + protected void stopNetStatPoll() { + netStatPollEnabled = false; + removeCallbacks(mPollNetStat); + Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); + } + + protected void restartRadio() { + Log.d(LOG_TAG, "************TURN OFF RADIO**************"); + cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); + 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), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + } + + private Runnable mPollNetStat = new Runnable() { + + public void run() { + long sent, received; + long preTxPkts = -1, preRxPkts = -1; + + Activity newActivity; + + preTxPkts = txPkts; + preRxPkts = rxPkts; + + // check if netstat is still valid to avoid NullPointerException after NTC + if (netstat != null) { + try { + txPkts = netstat.getMobileTxPackets(); + rxPkts = netstat.getMobileRxPackets(); + } catch (RemoteException e) { + txPkts = 0; + rxPkts = 0; + } + + //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + + if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = txPkts - preTxPkts; + received = rxPkts - preRxPkts; + + if ( sent > 0 && received > 0 ) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAINANDOUT; + } else if (sent > 0 && received == 0) { + if (phone.getState() == Phone.State.IDLE) { + sentSinceLastRecv += sent; + } else { + sentSinceLastRecv = 0; + } + newActivity = Activity.DATAOUT; + } else if (sent == 0 && received > 0) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAIN; + } else if (sent == 0 && received == 0) { + newActivity = Activity.NONE; + } else { + sentSinceLastRecv = 0; + newActivity = Activity.NONE; + } + + if (activity != newActivity) { + activity = newActivity; + phone.notifyDataActivity(); + } + } + + if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { + // we already have NUMBER_SENT_PACKETS sent without ack + if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { + mNoRecvPollCount++; + // Slow down the poll interval to let things happen + netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; + } else { + if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + " pkts since last received"); + // We've exceeded the threshold. Restart the radio. + netStatPollEnabled = false; + stopNetStatPoll(); + restartRadio(); + } + } else { + mNoRecvPollCount = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; + } + + if (netStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, netStatPollPeriod); + } + } + } + }; + + /** + * Returns true if the last fail cause is something that + * seems like it deserves an error notification. + * Transient errors are ignored + */ + private boolean + shouldPostNotification(FailCause cause) { + return (cause != FailCause.UNKNOWN); + } + + /** + * Return true if data connection need to be setup after disconnected due to + * reason. + * + * @param reason the reason why data is disconnected + * @return true if try setup data connection is need for this reason + */ + private boolean retryAfterDisconnected(String reason) { + boolean retry = true; + + if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || + Phone.REASON_DATA_DISABLED.equals(reason) ) { + retry = false; + } + return retry; + } + + private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { + if (state == State.FAILED) { + Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + + (nextReconnectDelay / 1000) + "s"); + + 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 Data Connection Unavailable notification " + + "-- likely transient error"); + } else { + notifyNoData(lastFailCauseCode); + } + } + } + + private void notifyNoData(FailCause lastFailCauseCode) { + setState(State.FAILED); + } + + protected void onRecordsLoaded() { + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } + + protected void onNVReady() { + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onTrySetupData() { + trySetupData(null); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRoamingOff() { + trySetupData(Phone.REASON_ROAMING_OFF); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRoamingOn() { + if (getDataOnRoamingEnabled()) { + trySetupData(Phone.REASON_ROAMING_ON); + } else { + if (DBG) log("Tear down data connection on roaming."); + cleanUpConnection(true, Phone.REASON_ROAMING_ON); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRadioAvailable() { + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(null); + + Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + } + + if (state != State.IDLE) { + cleanUpConnection(true, null); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRadioOffOrNotAvailable() { + // Make sure our reconnect delay starts at the initial value + // next time the radio comes on + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + } else { + if (DBG) log("Radio is off and clean up all connection"); + cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onDataSetupComplete(AsyncResult ar) { + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + + if (ar.exception == null) { + // everything is setup + notifyDefaultData(reason); + } else { + FailCause cause = (FailCause) (ar.result); + if(DBG) log("Data Connection setup failed " + cause); + + // No try for permanent failure + if (cause.isPermanentFail()) { + notifyNoData(cause); + } + + if (tryAgain(cause)) { + trySetupData(reason); + } else { + startDelayedRetry(cause, reason); + } + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onDisconnectDone(AsyncResult ar) { + if(DBG) log("EVENT_DISCONNECT_DONE"); + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + setState(State.IDLE); + phone.notifyDataConnection(reason); + if (retryAfterDisconnected(reason)) { + trySetupData(reason); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onVoiceCallStarted() { + if (state == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) { + stopNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onVoiceCallEnded() { + if (state == State.CONNECTED) { + if (!mCdmaPhone.mSST.isConcurrentVoiceAndData()) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + } else { + // clean slate after call end. + resetPollStats(); + } + } else { + // in case data setup was attempted when we were on a voice call + trySetupData(Phone.REASON_VOICE_CALL_ENDED); + } + } + + private boolean tryAgain(FailCause cause) { + return (cause != FailCause.RADIO_NOT_AVAILABLE) + && (cause != FailCause.RADIO_OFF) + && (cause != FailCause.RADIO_ERROR_RETRY) + && (cause != FailCause.NO_SIGNAL) + && (cause != FailCause.SIM_LOCKED); + } + + private void createAllDataConnectionList() { + dataConnectionList = new ArrayList(); + CdmaDataConnection dataConn; + + for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { + dataConn = new CdmaDataConnection(mCdmaPhone); + dataConnectionList.add(dataConn); + } + } + + private void destroyAllDataConnectionList() { + if(dataConnectionList != null) { + dataConnectionList.removeAll(dataConnectionList); + } + } + + private void onCdmaDataAttached() { + if (state == State.CONNECTED) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); + } else { + if (state == State.FAILED) { + cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } + trySetupData(Phone.REASON_CDMA_DATA_DETACHED); + } + } + + protected void onDataStateChanged (AsyncResult ar) { + if (ar.exception != null) { + // This is probably "radio not available" or something + // of that sort. If so, the whole connection is going + // to come down soon anyway + return; + } + + if (state == State.CONNECTED) { + Log.i(LOG_TAG, "Data connection has changed."); + + int cid = -1; + EventLog.List val = new EventLog.List(cid, + TelephonyManager.getDefault().getNetworkType()); + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); + + cleanUpConnection(true, null); + } + Log.i(LOG_TAG, "Data connection has changed."); + } + + String getInterfaceName() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getInterface(); + } + return null; + } + + protected String getIpAddress() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getIpAddress(); + } + return null; + } + + String getGateway() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getGatewayAddress(); + } + return null; + } + + protected String[] getDnsServers() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getDnsServers(); + } + return null; + } + + public ArrayList getAllDataConnections() { + return dataConnectionList; + } + + private void startDelayedRetry(FailCause cause, String reason) { + notifyNoData(cause); + reconnectAfterFail(cause, reason); + } + + public void handleMessage (Message msg) { + + switch (msg.what) { + case EVENT_RECORDS_LOADED: + onRecordsLoaded(); + break; + + case EVENT_NV_READY: + onNVReady(); + break; + + case EVENT_CDMA_DATA_DETACHED: + onCdmaDataAttached(); + break; + + case EVENT_DATA_STATE_CHANGED: + onDataStateChanged((AsyncResult) msg.obj); + break; + + default: + // handle the message in the super class DataConnectionTracker + super.handleMessage(msg); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..42c058333536ccd4ec08daf2a80edc3fef89e645 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -0,0 +1,394 @@ +/* + * 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.cdma; + + +import android.app.PendingIntent; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.SQLException; +import android.os.AsyncResult; +import android.os.Message; +import android.util.Config; +import android.util.Log; + +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SMSDispatcher; +//import com.android.internal.telephony.SMSDispatcher.SmsTracker; +import com.android.internal.telephony.cdma.SmsMessage; +import com.android.internal.telephony.cdma.sms.SmsEnvelope; +import com.android.internal.util.HexDump; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.HashMap; + + +final class CdmaSMSDispatcher extends SMSDispatcher { + private static final String TAG = "CDMA"; + + CdmaSMSDispatcher(CDMAPhone phone) { + super(phone); + } + + /** + * Called when a status report is received. This should correspond to + * a previously successful SEND. + * Is a special GSM function, should never be called in CDMA!! + * + * @param ar AsyncResult passed into the message handler. ar.result should + * be a String representing the status report PDU, as ASCII hex. + */ + protected void handleStatusReport(AsyncResult ar) { + Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!"); + } + + /** + * Dispatches an incoming SMS messages. + * + * @param smsb the incoming message from the phone + */ + protected void dispatchMessage(SmsMessageBase smsb) { + + // If sms is null, means there was a parsing error. + // TODO: Should NAK this. + if (smsb == null) { + return; + } + SmsMessage sms = (SmsMessage) smsb; + int teleService; + boolean handled = false; + + // Decode BD stream and set sms variables. + sms.parseSms(); + teleService = sms.getTeleService(); + + // Teleservices W(E)MT and VMN are handled together: + if ((SmsEnvelope.TELESERVICE_WMT == teleService) + ||(SmsEnvelope.TELESERVICE_WEMT == teleService) + ||(SmsEnvelope.TELESERVICE_VMN == teleService)){ + // From here on we need decoded BD. + // Special case the message waiting indicator messages + if (sms.isMWISetMessage()) { + ((CDMAPhone) mPhone).updateMessageWaitingIndicator(true); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator set SMS shouldStore=" + !handled); + } + } else if (sms.isMWIClearMessage()) { + ((CDMAPhone) mPhone).updateMessageWaitingIndicator(false); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator clear SMS shouldStore=" + !handled); + } + } + } + + if (null == sms.getUserData()){ + handled = true; + if (Config.LOGD) { + Log.d(TAG, "Received SMS without user data"); + } + } + + if (handled) return; + + if (SmsEnvelope.TELESERVICE_WAP == teleService){ + processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress()); + return; + } + + // Parse the headers to see if this is partial, or port addressed + int referenceNumber = -1; + int count = 0; + int sequence = 0; + int destPort = -1; + // From here on we need BD distributed to SMS member variables. + + SmsHeader header = sms.getUserDataHeader(); + if (header != null) { + for (SmsHeader.Element element : header.getElements()) { + try { + switch (element.getID()) { + case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = data[0] & 0xff; + count = data[1] & 0xff; + sequence = data[2] & 0xff; + + // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence + // is zero, or sequence > count, ignore the entire element + if (count == 0 || sequence == 0 || sequence > count) { + referenceNumber = -1; + } + break; + } + + case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); + count = data[2] & 0xff; + sequence = data[3] & 0xff; + + // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence + // is zero, or sequence > count, ignore the entire element + if (count == 0 || sequence == 0 || sequence > count) { + referenceNumber = -1; + } + break; + } + + case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { + byte[] data = element.getData(); + + destPort = (data[0] & 0xff) << 8; + destPort |= (data[1] & 0xff); + + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + Log.e(TAG, "Bad element in header", e); + return; // TODO: NACK the message or something, don't just discard. + } + } + } + + if (referenceNumber == -1) { + // notify everyone of the message if it isn't partial + byte[][] pdus = new byte[1][]; + pdus[0] = sms.getPdu(); + + if (destPort != -1) {// GSM-style WAP indication + if (destPort == SmsHeader.PORT_WAP_PUSH) { + mWapPush.dispatchWapPdu(sms.getUserData()); + } + // The message was sent to a port, so concoct a URI for it + dispatchPortAddressedPdus(pdus, destPort); + } else { + // It's a normal message, dispatch it + dispatchPdus(pdus); + } + } else { + // Process the message part + processMessagePart(sms, referenceNumber, sequence, count, destPort); + } + } + + /** + * Processes inbound messages that are in the WAP-WDP PDU format. See + * wap-259-wdp-20010614-a section 6.5 for details on the WAP-WDP PDU format. + * WDP segments are gathered until a datagram completes and gets dispatched. + * + * @param pdu The WAP-WDP PDU segment + */ + protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) { + int segment; + int totalSegments; + int index = 0; + int msgType; + + int sourcePort; + int destinationPort; + + msgType = pdu[index++]; + if (msgType != 0){ + Log.w(TAG, "Received a WAP SMS which is not WDP. Discard."); + return; + } + totalSegments = pdu[index++]; // >=1 + segment = pdu[index++]; // >=0 + + //process WDP segment + sourcePort = (0xFF & pdu[index++]) << 8; + sourcePort |= 0xFF & pdu[index++]; + destinationPort = (0xFF & pdu[index++]) << 8; + destinationPort |= 0xFF & pdu[index++]; + + // Lookup all other related parts + StringBuilder where = new StringBuilder("reference_number ="); + where.append(referenceNumber); + where.append(" AND address = ?"); + String[] whereArgs = new String[] {address}; + + Log.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address + + ", src-port = " + sourcePort + ", dst-port = " + destinationPort + + ", ID = " + referenceNumber + ", segment# = " + segment + "/" + totalSegments); + + byte[][] pdus = null; + Cursor cursor = null; + try { + cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null); + int cursorCount = cursor.getCount(); + if (cursorCount != totalSegments - 1) { + // We don't have all the parts yet, store this one away + ContentValues values = new ContentValues(); + values.put("date", new Long(0)); + values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index)); + values.put("address", address); + values.put("reference_number", referenceNumber); + values.put("count", totalSegments); + values.put("sequence", segment); + values.put("destination_port", destinationPort); + + mResolver.insert(mRawUri, values); + + return; + } + + // All the parts are in place, deal with them + int pduColumn = cursor.getColumnIndex("pdu"); + int sequenceColumn = cursor.getColumnIndex("sequence"); + + pdus = new byte[totalSegments][]; + for (int i = 0; i < cursorCount; i++) { + cursor.moveToNext(); + int cursorSequence = (int)cursor.getLong(sequenceColumn); + pdus[cursorSequence] = HexDump.hexStringToByteArray( + cursor.getString(pduColumn)); + } + // The last part will be added later + + // Remove the parts from the database + mResolver.delete(mRawUri, where.toString(), whereArgs); + } catch (SQLException e) { + Log.e(TAG, "Can't access multipart SMS database", e); + return; // TODO: NACK the message or something, don't just discard. + } finally { + if (cursor != null) cursor.close(); + } + + // Build up the data stream + ByteArrayOutputStream output = new ByteArrayOutputStream(); + for (int i = 0; i < totalSegments-1; i++) { + // reassemble the (WSP-)pdu + output.write(pdus[i], 0, pdus[i].length); + } + + // This one isn't in the DB, so add it + output.write(pdu, index, pdu.length - index); + + byte[] datagram = output.toByteArray(); + // Dispatch the PDU to applications + switch (destinationPort) { + case SmsHeader.PORT_WAP_PUSH: + // Handle the PUSH + mWapPush.dispatchWapPdu(datagram); + break; + + default:{ + pdus = new byte[1][]; + pdus[0] = datagram; + // The messages were sent to any other WAP port + dispatchPortAddressedPdus(pdus, destinationPort); + break; + } + } + } + + /** {@inheritDoc} */ + protected void sendMultipartText(String destinationAddress, String scAddress, + ArrayList parts, ArrayList sentIntents, + ArrayList deliveryIntents) { + + int ref = ++sConcatenatedRef & 0xff; + + for (int i = 0, count = parts.size(); i < count; i++) { + // build SmsHeader data + byte[] data = new byte[5]; + data[0] = (byte) SmsHeader.CONCATENATED_8_BIT_REFERENCE; + data[1] = (byte) 3; // 3 bytes follow + data[2] = (byte) ref; // reference #, unique per message + data[3] = (byte) count; // total part count + data[4] = (byte) (i + 1); // 1-based sequence + + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, data); + + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + } + + protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + + /** {@inheritDoc} */ + protected void sendSms(SmsTracker tracker) { + HashMap map = tracker.mData; + + byte smsc[] = (byte[]) map.get("smsc"); + byte pdu[] = (byte[]) map.get("pdu"); + + Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); + + mCm.sendCdmaSms(pdu, reply); + } + + /** {@inheritDoc} */ + protected void sendMultipartSms (SmsTracker tracker) { + Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented"); + } + + /** {@inheritDoc} */ + protected void acknowledgeLastIncomingSms(boolean success, Message response){ + // FIXME unit test leaves cm == null. this should change + if (mCm != null) { + mCm.acknowledgeLastIncomingCdmaSms(success, response); + } + } + + /** {@inheritDoc} */ + protected void activateCellBroadcastSms(int activate, Message response) { + mCm.activateCdmaBroadcastSms(activate, response); + } + + /** {@inheritDoc} */ + protected void getCellBroadcastSmsConfig(Message response) { + mCm.getCdmaBroadcastConfig(response); + } + + /** {@inheritDoc} */ + protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { + mCm.setCdmaBroadcastConfig(configValuesArray, response); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java new file mode 100644 index 0000000000000000000000000000000000000000..d5cad1ca9cee956eba0bea6008ddebfe732d2e08 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -0,0 +1,1020 @@ +/* + * 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.cdma; + +import android.app.AlarmManager; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.ContentObserver; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.provider.Checkin; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.provider.Telephony.Intents; +import android.telephony.ServiceState; +import android.telephony.cdma.CdmaCellLocation; +import android.text.TextUtils; +import android.util.EventLog; +import android.util.Log; +import android.util.TimeUtils; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnectionTracker; +// pretty sure importing stuff from GSM is bad: +import com.android.internal.telephony.gsm.MccTable; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.TelephonyEventLog; +import com.android.internal.telephony.TelephonyIntents; + +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_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISMANUAL; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; + +import java.util.Arrays; +import java.util.Date; +import java.util.TimeZone; + +/** + * {@hide} + */ +final class CdmaServiceStateTracker extends ServiceStateTracker { + //***** Instance Variables + CDMAPhone phone; + CdmaCellLocation cellLoc; + CdmaCellLocation newCellLoc; + + int rssi = 99; // signal strength 0-31, 99=unknown + // That's "received signal strength indication" fyi + + /** + * The access technology currently in use: DATA_ACCESS_ + */ + private int networkType = 0; + private int newNetworkType = 0; + + private boolean mCdmaRoaming = false; + + private int cdmaDataConnectionState = -1;//Initial we assume no data connection + private int newCdmaDataConnectionState = -1;//Initial we assume no data connection + private int mRegistrationState = -1; + private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList(); + private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList(); + + private boolean mGotCountryCode = false; + + // We can't register for SIM_RECORDS_LOADED immediately because the + // SIMRecords object may not be instantiated yet. + private boolean mNeedToRegForRuimLoaded; + + // Keep track of SPN display rules, so we only broadcast intent if something changes. + private String curSpn = null; + private String curPlmn = null; + private int curSpnRule = 0; + + //***** Constants + static final String LOG_TAG = "CDMA"; + static final String TMUK = "23430"; + + private ContentResolver cr; + + private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { + @Override + public void onChange(boolean selfChange) { + Log.i("CdmaServiceStateTracker", "Auto time state called ..."); + //NOTE in CDMA NITZ is not used + } + }; + + + //***** Constructors + + public CdmaServiceStateTracker(CDMAPhone phone) { + super(); + + this.phone = phone; + cm = phone.mCM; + ss = new ServiceState(); + newSS = new ServiceState(); + cellLoc = new CdmaCellLocation(); + newCellLoc = new CdmaCellLocation(); + + cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); + + cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null); + cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); + + cm.registerForRUIMReady(this, EVENT_RUIM_READY, null); + + phone.registerForNvLoaded(this, EVENT_NV_LOADED,null); + + // system setting property AIRPLANE_MODE_ON is set in Settings. + int airplaneMode = Settings.System.getInt( + phone.getContext().getContentResolver(), + Settings.System.AIRPLANE_MODE_ON, 0); + mDesiredPowerState = ! (airplaneMode > 0); + + cr = phone.getContext().getContentResolver(); + cr.registerContentObserver( + Settings.System.getUriFor(Settings.System.AUTO_TIME), true, + mAutoTimeObserver); + setRssiDefaultValues(); + + mNeedToRegForRuimLoaded = true; + } + + public void dispose() { + //Unregister for all events + cm.unregisterForAvailable(this); + cm.unregisterForRadioStateChanged(this); + cm.unregisterForNetworkStateChanged(this); + cm.unregisterForRUIMReady(this); + phone.unregisterForNvLoaded(this); + phone.mRuimRecords.unregisterForRecordsLoaded(this); + cm.unSetOnSignalStrengthUpdate(this); + cr.unregisterContentObserver(this.mAutoTimeObserver); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "CdmaServiceStateTracker finalized"); + } + + void registerForNetworkAttach(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + networkAttachedRegistrants.add(r); + + if (ss.getState() == ServiceState.STATE_IN_SERVICE) { + r.notifyRegistrant(); + } + } + + void unregisterForNetworkAttach(Handler h) { + networkAttachedRegistrants.remove(h); + } + + /** + * Registration point for transition into Data attached. + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + /*protected*/ void + registerForCdmaDataConnectionAttached(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + cdmaDataConnectionAttachedRegistrants.add(r); + + if (cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT + || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 + || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) { + r.notifyRegistrant(); + } + } + void unregisterForCdmaDataConnectionAttached(Handler h) { + cdmaDataConnectionAttachedRegistrants.remove(h); + } + + /** + * Registration point for transition into Data detached. + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + /*protected*/ void + registerForCdmaDataConnectionDetached(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + cdmaDataConnectionDetachedRegistrants.add(r); + + if (cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT + && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 + && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) { + r.notifyRegistrant(); + } + } + void unregisterForCdmaDataConnectionDetached(Handler h) { + cdmaDataConnectionDetachedRegistrants.remove(h); + } + + //***** Called from CDMAPhone + public void + getLacAndCid(Message onComplete) { + cm.getRegistrationState(obtainMessage( + EVENT_GET_LOC_DONE_CDMA, onComplete)); + } + + + //***** Overridden from ServiceStateTracker + public void + handleMessage (Message msg) { + AsyncResult ar; + int[] ints; + String[] strings; + + switch (msg.what) { + case EVENT_RADIO_AVAILABLE: + //this is unnecessary + //setPowerStateToDesired(); + break; + + case EVENT_RUIM_READY: + // The RUIM is now ready i.e if it was locked + // it has been unlocked. At this stage, the radio is already + // powered on. + if (mNeedToRegForRuimLoaded) { + phone.mRuimRecords.registerForRecordsLoaded(this, + EVENT_RUIM_RECORDS_LOADED, null); + mNeedToRegForRuimLoaded = false; + } + // restore the previous network selection. + phone.restoreSavedNetworkSelection(null); + pollState(); + // Signal strength polling stops when radio is off + queueNextSignalStrengthPoll(); + break; + + case EVENT_RADIO_STATE_CHANGED: + // This will do nothing in the radio not + // available case + setPowerStateToDesired(); + pollState(); + break; + + case EVENT_NETWORK_STATE_CHANGED_CDMA: + pollState(); + break; + + case EVENT_GET_SIGNAL_STRENGTH: + // This callback is called when signal strength is polled + // all by itself + + if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isGsm())) { + // Polling will continue when radio turns back on + return; + } + ar = (AsyncResult) msg.obj; + onSignalStrengthResult(ar); + queueNextSignalStrengthPoll(); + + break; + + case EVENT_GET_LOC_DONE_CDMA: + ar = (AsyncResult) msg.obj; + + if (ar.exception == null) { + String states[] = (String[])ar.result; + int baseStationId = -1; + int baseStationLongitude = -1; + int baseStationLatitude = -1; + + int baseStationData[] = { + -1, // baseStationId + -1, // baseStationLatitude + -1 // baseStationLongitude + }; + + if (states.length == 3) { + for(int i = 0; i < states.length; i++) { + try { + if (states[i] != null && states[i].length() > 0) { + baseStationData[i] = Integer.parseInt(states[i], 16); + } + } catch (NumberFormatException ex) { + Log.w(LOG_TAG, "error parsing cell location data: " + ex); + } + } + } + + // only update if cell location really changed + if (cellLoc.getBaseStationId() != baseStationData[0] + || cellLoc.getBaseStationLatitude() != baseStationData[1] + || cellLoc.getBaseStationLongitude() != baseStationData[2]) { + cellLoc.setCellLocationData(baseStationData[0], + baseStationData[1], + baseStationData[2]); + phone.notifyLocationChanged(); + } + } + + if (ar.userObj != null) { + AsyncResult.forMessage(((Message) ar.userObj)).exception + = ar.exception; + ((Message) ar.userObj).sendToTarget(); + } + break; + + case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA: //Fall through + case EVENT_POLL_STATE_REGISTRATION_CDMA: //Fall through + case EVENT_POLL_STATE_OPERATOR_CDMA: + ar = (AsyncResult) msg.obj; + handlePollStateResult(msg.what, ar); + break; + + case EVENT_POLL_SIGNAL_STRENGTH: + // Just poll signal strength...not part of pollState() + + cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); + break; + + case EVENT_SIGNAL_STRENGTH_UPDATE: + // This is a notification from + // CommandsInterface.setOnSignalStrengthUpdate + + ar = (AsyncResult) msg.obj; + + // The radio is telling us about signal strength changes + // we don't have to ask it + dontPollSignalStrength = true; + + onSignalStrengthResult(ar); + break; + + case EVENT_RUIM_RECORDS_LOADED: + case EVENT_NV_LOADED: + updateSpnDisplay(); + break; + + case EVENT_LOCATION_UPDATES_ENABLED: + ar = (AsyncResult) msg.obj; + + if (ar.exception == null) { + getLacAndCid(null); + } + break; + + default: + Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); + break; + } + } + + //***** Private Instance Methods + + protected void setPowerStateToDesired() + { + // If we want it on and it's off, turn it on + if (mDesiredPowerState + && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { + 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(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val); + } + dcTracker.cleanConnectionBeforeRadioOff(); + + // poll data state up to 15 times, with a 100ms delay + // totaling 1.5 sec. Normal data disable action will finish in 100ms. + for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { + if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED + && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { + Log.d(LOG_TAG, "Data shutdown complete."); + break; + } + SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); + } + // If it's on and available and we want it off.. + cm.setRadioPower(false, null); + } // Otherwise, we're in the desired state + } + + protected void updateSpnDisplay() { + + // TODO Check this method again, because it is not sure at the moment how + // the RUIM handles the SIM stuff + + //int rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric()); + String spn = null; //phone.mRuimRecords.getServiceProviderName(); + String plmn = ss.getOperatorAlphaLong(); + + if (!TextUtils.equals(this.curPlmn, plmn)) { + //TODO (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; + boolean showSpn = false; + //TODO (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; + boolean showPlmn = true; + Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); + intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); + intent.putExtra(Intents.EXTRA_SPN, spn); + intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); + intent.putExtra(Intents.EXTRA_PLMN, plmn); + phone.getContext().sendStickyBroadcast(intent); + } + + //curSpnRule = rule; + //curSpn = spn; + this.curPlmn = plmn; + } + + /** + * Handle the result of one of the pollState()-related requests + */ + + protected void + handlePollStateResult (int what, AsyncResult ar) { + int ints[]; + String states[]; + + // Ignore stale requests from last poll + if (ar.userObj != pollingContext) return; + + if (ar.exception != null) { + CommandException.Error err=null; + + if (ar.exception instanceof CommandException) { + err = ((CommandException)(ar.exception)).getCommandError(); + } + + if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { + // Radio has crashed or turned off + cancelPollState(); + return; + } + + if (!cm.getRadioState().isOn()) { + // Radio has crashed or turned off + cancelPollState(); + return; + } + + 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", + ar.exception); + } + } else try { + switch (what) { + case EVENT_POLL_STATE_REGISTRATION_CDMA: + //offset, because we don't want the first 3 values in the int-array + final int offset = 3; + states = (String[])ar.result; + + int responseValuesRegistrationState[] = { + -1, //[0] radioTechnology + -1, //[1] baseStationId + -1, //[2] baseStationLatitude + -1, //[3] baseStationLongitude + 0, //[4] cssIndicator; init with 0, because it is treated as a boolean + -1, //[5] systemId + -1, //[6] networkId + -1, //[7] TSB-58 Roaming indicator // NEWRIL:TODO UNUSED + -1, //[8] Indicates if current system is in PRL // NEWRIL:TODO UNUSED + -1, //[9] Is default roaming indicator from PRL // NEWRIL:TODO UNUSED + -1, //[10] If registration state is 3 this is reason for denial // NEWRIL:TODO UNUSED + }; + + if (states.length > 0) { + try { + this.mRegistrationState = Integer.parseInt(states[0]); + if (states.length >= 10) { + for(int i = 0; i < states.length - offset; i++) { + if (states[i + offset] != null + && states[i + offset].length() > 0) { + try { + responseValuesRegistrationState[i] = + Integer.parseInt(states[i + offset], 16); + } + catch(NumberFormatException ex) { + Log.w(LOG_TAG, "Warning! There is an unexpected value" + + "returned as response from " + + "RIL_REQUEST_REGISTRATION_STATE."); + } + } + } + } + else { + Log.e(LOG_TAG, "Too less parameters returned from" + + " RIL_REQUEST_REGISTRATION_STATE"); + } + } catch (NumberFormatException ex) { + Log.w(LOG_TAG, "error parsing RegistrationState: " + ex); + } + } + + mCdmaRoaming = regCodeIsRoaming(this.mRegistrationState); + this.newCdmaDataConnectionState = + radioTechnologyToServiceState(responseValuesRegistrationState[0]); + newSS.setState (regCodeToServiceState(this.mRegistrationState)); + newSS.setRadioTechnology(responseValuesRegistrationState[0]); + newSS.setCssIndicator(responseValuesRegistrationState[4]); + newSS.setSystemAndNetworkId(responseValuesRegistrationState[5], + responseValuesRegistrationState[6]); + + newNetworkType = responseValuesRegistrationState[0]; + + // values are -1 if not available + newCellLoc.setCellLocationData(responseValuesRegistrationState[1], + responseValuesRegistrationState[2], + responseValuesRegistrationState[3]); + break; + + case EVENT_POLL_STATE_OPERATOR_CDMA: + String opNames[] = (String[])ar.result; + + if (opNames != null && opNames.length >= 3) { + newSS.setOperatorName (opNames[0], opNames[1], opNames[2]); + } + break; + + case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA: + ints = (int[])ar.result; + newSS.setIsManualSelection(ints[0] == 1); + break; + default: + Log.e(LOG_TAG, "RIL response handle in wrong phone!" + + " Expected CDMA RIL request and get GSM RIL request."); + break; + } + + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "Exception while polling service state. " + + "Probably malformed RIL response.", ex); + } + + pollingContext[0]--; + + if (pollingContext[0] == 0) { + newSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, newSS)); + + switch(this.mRegistrationState) { + case ServiceState.REGISTRATION_STATE_HOME_NETWORK: + newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_HOME_NETWORK); + break; + case ServiceState.REGISTRATION_STATE_ROAMING: + newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_ROAMING); + break; + case ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE: + newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE); + break; + default: + Log.w(LOG_TAG, "Received a different registration state, " + + "but don't changed the extended cdma roaming mode."); + } + pollStateDone(); + } + + } + + private void setRssiDefaultValues() { + rssi = 99; + } + + /** + * A complete "service state" from our perspective is + * composed of a handful of separate requests to the radio. + * + * We make all of these requests at once, but then abandon them + * and start over again if the radio notifies us that some + * event has changed + */ + + private void + pollState() { + pollingContext = new int[1]; + pollingContext[0] = 0; + + switch (cm.getRadioState()) { + case RADIO_UNAVAILABLE: + newSS.setStateOutOfService(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + + case RADIO_OFF: + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + + case SIM_NOT_READY: + case SIM_LOCKED_OR_ABSENT: + case SIM_READY: + log("Radio Technology Change ongoing, setting SS to off"); + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + + default: + // Issue all poll-related commands at once + // then count down the responses, which + // are allowed to arrive out-of-order + + pollingContext[0]++; + //RIL_REQUEST_OPERATOR is necessary for CDMA + cm.getOperator( + obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); + + pollingContext[0]++; + //RIL_REQUEST_REGISTRATION_STATE is necessary for CDMA + cm.getRegistrationState( + obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, pollingContext)); + + pollingContext[0]++; + //RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE necessary for CDMA + cm.getNetworkSelectionMode( + obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA, pollingContext)); + break; + } + } + + private static String networkTypeToString(int type) { + String ret = "unknown"; + + switch (type) { + case DATA_ACCESS_CDMA_IS95A: + case DATA_ACCESS_CDMA_IS95B: + ret = "CDMA"; + break; + case DATA_ACCESS_CDMA_1xRTT: + ret = "CDMA - 1xRTT"; + break; + case DATA_ACCESS_CDMA_EvDo_0: + ret = "CDMA - EvDo rev. 0"; + break; + case DATA_ACCESS_CDMA_EvDo_A: + ret = "CDMA - EvDo rev. A"; + break; + default: + if (DBG) { + Log.e(LOG_TAG, "Wrong network. Can not return a string."); + } + break; + } + + return ret; + } + + private void + pollStateDone() { + if (DBG) { + Log.d(LOG_TAG, "Poll ServiceState done: " + + " oldSS=[" + ss ); + Log.d(LOG_TAG, "Poll ServiceState done: " + + " newSS=[" + newSS); + } + + boolean hasRegistered = + ss.getState() != ServiceState.STATE_IN_SERVICE + && newSS.getState() == ServiceState.STATE_IN_SERVICE; + + boolean hasDeregistered = + ss.getState() == ServiceState.STATE_IN_SERVICE + && newSS.getState() != ServiceState.STATE_IN_SERVICE; + + boolean hasCdmaDataConnectionAttached = + (this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT + && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 + && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && (this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT + || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 + || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A); + + boolean hasCdmaDataConnectionDetached = + (this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT + || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 + || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && (this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT + && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 + && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A); + + boolean hasCdmaDataConnectionChanged = + cdmaDataConnectionState != newCdmaDataConnectionState; + + boolean hasNetworkTypeChanged = networkType != newNetworkType; + + boolean hasChanged = !newSS.equals(ss); + + boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming(); + + boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming(); + + boolean hasLocationChanged = !newCellLoc.equals(cellLoc); + + ServiceState tss; + tss = ss; + ss = newSS; + newSS = tss; + // clean slate for next time + newSS.setStateOutOfService(); + + CdmaCellLocation tcl = cellLoc; + cellLoc = newCellLoc; + newCellLoc = tcl; + + cdmaDataConnectionState = newCdmaDataConnectionState; + networkType = newNetworkType; + + newSS.setStateOutOfService(); // clean slate for next time + + if (hasNetworkTypeChanged) { + phone.setSystemProperty(PROPERTY_DATA_NETWORK_TYPE, + networkTypeToString(networkType)); + } + + if (hasRegistered) { + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_REGISTERED, 1, 0.0); + networkAttachedRegistrants.notifyRegistrants(); + } + + if (hasChanged) { + String operatorNumeric; + + phone.setSystemProperty(PROPERTY_OPERATOR_ALPHA, + ss.getOperatorAlphaLong()); + + operatorNumeric = ss.getOperatorNumeric(); + phone.setSystemProperty(PROPERTY_OPERATOR_NUMERIC, operatorNumeric); + + if (operatorNumeric == null) { + phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, ""); + } else { + String iso = ""; + try{ + iso = MccTable.countryCodeForMcc(Integer.parseInt( + operatorNumeric.substring(0,3))); + } catch ( NumberFormatException ex){ + Log.w(LOG_TAG, "countryCodeForMcc error" + ex); + } catch ( StringIndexOutOfBoundsException ex) { + Log.w(LOG_TAG, "countryCodeForMcc error" + ex); + } + + phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso); + mGotCountryCode = true; + } + + phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING, + ss.getRoaming() ? "true" : "false"); + phone.setSystemProperty(PROPERTY_OPERATOR_ISMANUAL, + ss.getIsManualSelection() ? "true" : "false"); + + updateSpnDisplay(); + phone.notifyServiceStateChanged(ss); + } + + if (hasCdmaDataConnectionAttached) { + cdmaDataConnectionAttachedRegistrants.notifyRegistrants(); + } + + if (hasCdmaDataConnectionDetached) { + cdmaDataConnectionDetachedRegistrants.notifyRegistrants(); + } + + if (hasCdmaDataConnectionChanged) { + phone.notifyDataConnection(null); + } + + if (hasRoamingOn) { + roamingOnRegistrants.notifyRegistrants(); + } + + if (hasRoamingOff) { + roamingOffRegistrants.notifyRegistrants(); + } + + if (hasLocationChanged) { + phone.notifyLocationChanged(); + } + } + + /** + * Returns a TimeZone object based only on parameters from the NITZ string. + */ + private TimeZone getNitzTimeZone(int offset, boolean dst, long when) { + TimeZone guess = findTimeZone(offset, dst, when); + if (guess == null) { + // Couldn't find a proper timezone. Perhaps the DST data is wrong. + guess = findTimeZone(offset, !dst, when); + } + if (DBG) { + Log.d(LOG_TAG, "getNitzTimeZone returning " + + (guess == null ? guess : guess.getID())); + } + return guess; + } + + private TimeZone findTimeZone(int offset, boolean dst, long when) { + int rawOffset = offset; + if (dst) { + rawOffset -= 3600000; + } + String[] zones = TimeZone.getAvailableIDs(rawOffset); + TimeZone guess = null; + Date d = new Date(when); + for (String zone : zones) { + TimeZone tz = TimeZone.getTimeZone(zone); + if (tz.getOffset(when) == offset && + tz.inDaylightTime(d) == dst) { + guess = tz; + break; + } + } + + return guess; + } + + private void + queueNextSignalStrengthPoll() { + if (dontPollSignalStrength || (cm.getRadioState().isGsm())) { + // The radio is telling us about signal strength changes + // we don't have to ask it + return; + } + + Message msg; + + msg = obtainMessage(); + msg.what = EVENT_POLL_SIGNAL_STRENGTH; + + // TODO Done't poll signal strength if screen is off + sendMessageDelayed(msg, POLL_PERIOD_MILLIS); + } + + /** + * send signal-strength-changed notification if rssi changed + * Called both for solicited and unsolicited signal stength updates + */ + private void + onSignalStrengthResult(AsyncResult ar) { + int oldRSSI = rssi; + + if (ar.exception != null) { + // 99 = unknown + // most likely radio is resetting/disconnected + rssi = 99; + } else { + int[] ints = (int[])ar.result; + + // bug 658816 seems to be a case where the result is 0-length + if (ints.length != 0) { + rssi = ints[0]; + } else { + Log.e(LOG_TAG, "Bogus signal strength response"); + rssi = 99; + } + } + + if (rssi != oldRSSI) { + try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after + // POLL_PERIOD_MILLIS) during Radio Technology Change) + phone.notifySignalStrength(); + } catch (NullPointerException ex) { + log("onSignalStrengthResult() Phone already destroyed: " + ex + + "Signal Stranth not notified"); + } + } + } + + + private int radioTechnologyToServiceState(int code) { + int retVal = ServiceState.RADIO_TECHNOLOGY_UNKNOWN; + switch(code) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + break; + case 6: + retVal = ServiceState.RADIO_TECHNOLOGY_1xRTT; + break; + case 7: + retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_0; + break; + case 8: + retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_A; + break; + default: + Log.e(LOG_TAG, "Wrong radioTechnology code."); + break; + } + return(retVal); + } + + /** code is registration state 0-5 from TS 27.007 7.2 */ + private int + regCodeToServiceState(int code) { + switch (code) { + case 0: // Not searching and not registered + return ServiceState.STATE_OUT_OF_SERVICE; + case 1: + return ServiceState.STATE_IN_SERVICE; + case 2: // 2 is "searching", fall through + case 3: // 3 is "registration denied", fall through + case 4: // 4 is "unknown" no vaild in current baseband + return ServiceState.STATE_OUT_OF_SERVICE; + case 5:// fall through + case 6: + // Registered and: roaming (5) or roaming affiliates (6) + return ServiceState.STATE_IN_SERVICE; + + default: + Log.w(LOG_TAG, "unexpected service state " + code); + return ServiceState.STATE_OUT_OF_SERVICE; + } + } + + /** + * @return The current CDMA data connection state. ServiceState.RADIO_TECHNOLOGY_1xRTT or + * ServiceState.RADIO_TECHNOLOGY_EVDO is the same as "attached" and + * ServiceState.RADIO_TECHNOLOGY_UNKNOWN is the same as detached. + */ + /*package*/ int getCurrentCdmaDataConnectionState() { + return cdmaDataConnectionState; + } + + /** + * code is registration state 0-5 from TS 27.007 7.2 + * returns true if registered roam, false otherwise + */ + private boolean + regCodeIsRoaming (int code) { + // 5 is "in service -- roam" + return 5 == code; + } + + /** + * Set roaming state when cdmaRoaming is true and ons is different from spn + * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming + * @param s ServiceState hold current ons + * @return true for roaming state set + */ + private + boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) { + String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty"); + + String onsl = s.getOperatorAlphaLong(); + String onss = s.getOperatorAlphaShort(); + + boolean equalsOnsl = onsl != null && spn.equals(onsl); + boolean equalsOnss = onss != null && spn.equals(onss); + + return cdmaRoaming && !(equalsOnsl || equalsOnss); + } + + private boolean getAutoTime() { + try { + return Settings.System.getInt(phone.getContext().getContentResolver(), + Settings.System.AUTO_TIME) > 0; + } catch (SettingNotFoundException snfe) { + return true; + } + } + + /** + * @return true if phone is camping on a technology + * that could support voice and data simultaneously. + */ + boolean isConcurrentVoiceAndData() { + + // Note: it needs to be confirmed which CDMA network types + // can support voice and data calls concurrently. + // For the time-being, the return value will be false. + return false; + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java new file mode 100644 index 0000000000000000000000000000000000000000..c226b62eef4391a1559fdc4f86d12d747d557f89 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java @@ -0,0 +1,312 @@ +/* + * 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.cdma; + +import android.content.Context; +import android.os.*; +import android.util.Log; + +import com.android.internal.telephony.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * {@hide} + * + */ +public final class FeatureCode extends Handler implements MmiCode { + static final String LOG_TAG = "CDMA"; + + //***** Constants + + // Call Forwarding + static final String FC_CF_ACTIVATE = "72"; + static final String FC_CF_DEACTIVATE = "73"; + static final String FC_CF_FORWARD_TO_NUMBER = "56"; + + // Call Forwarding Busy Line + static final String FC_CFBL_ACTIVATE = "90"; + static final String FC_CFBL_DEACTIVATE = "91"; + static final String FC_CFBL_FORWARD_TO_NUMBER = "40"; + + // Call Forwarding Don't Answer + static final String FC_CFDA_ACTIVATE = "92"; + static final String FC_CFDA_DEACTIVATE = "93"; + static final String FC_CFDA_FORWARD_TO_NUMBER = "42"; + + // Cancel Call Waiting + static final String FC_CCW = "70"; + + // Usage Sensitive Three-way Calling + static final String FC_3WC = "71"; + + // Do Not Disturb + static final String FC_DND_ACTIVATE = "78"; + static final String FC_DND_DEACTIVATE = "79"; + + // Who Called Me? + static final String FC_WHO = "51"; + + // Rejection of Undesired Annoying Calls + static final String FC_RUAC_ACTIVATE = "60"; + static final String FC_RUAC_DEACTIVATE = "80"; + + // Calling Number Delivery + // Calling Number Identification Presentation + static final String FC_CNIP = "65"; + // Calling Number Identification Restriction + static final String FC_CNIR = "85"; + + + //***** Event Constants + + static final int EVENT_SET_COMPLETE = 1; + static final int EVENT_CDMA_FLASH_COMPLETED = 2; + + + //***** Instance Variables + + CDMAPhone phone; + Context context; + + String action; // '*' in CDMA + String sc; // Service Code + String poundString; // Entire Flash string + String dialingNumber; + + /** Set to true in processCode, not at newFromDialString time */ + + State state = State.PENDING; + CharSequence message; + + //***** Class Variables + + + // Flash Code Pattern + + static Pattern sPatternSuppService = Pattern.compile( + "((\\*)(\\d{2,3})(#?)([^*#]*)?)(.*)"); +/* 1 2 3 4 5 6 + + 1 = Full string up to and including # + 2 = action + 3 = service code + 4 = separator + 5 = dialing number +*/ + + static final int MATCH_GROUP_POUND_STRING = 1; + static final int MATCH_GROUP_ACTION_STRING = 2; + static final int MATCH_GROUP_SERVICE_CODE = 3; + static final int MATCH_GROUP_DIALING_NUMBER = 5; + + + //***** Public Class methods + + /** + * Some dial strings in CDMA are defined to do non-call setup + * things, such as set supplementary service settings (eg, call + * forwarding). These are generally referred to as "Feature Codes". + * We look to see if the dial string contains a valid Feature code (potentially + * with a dial string at the end as well) and return info here. + * + * If the dial string contains no Feature code, we return an instance with + * only "dialingNumber" set + * + * Please see also S.R0006-000-A v2.0 "Wireless Features Description" + */ + + static FeatureCode newFromDialString(String dialString, CDMAPhone phone) { + Matcher m; + FeatureCode ret = null; + + m = sPatternSuppService.matcher(dialString); + + // Is this formatted like a standard supplementary service code? + if (m.matches()) { + ret = new FeatureCode(phone); + ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING)); + ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION_STRING)); + ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE)); + ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER)); + } + + return ret; + } + + //***** Private Class methods + + /** make empty strings be null. + * Java regexp returns empty strings for empty groups + */ + private static String makeEmptyNull (String s) { + if (s != null && s.length() == 0) return null; + + return s; + } + + /** returns true of the string is empty or null */ + private static boolean isEmptyOrNull(CharSequence s) { + return s == null || (s.length() == 0); + } + + static boolean isServiceCodeCallForwarding(String sc) { + return sc != null && + (sc.equals(FC_CF_ACTIVATE) + || sc.equals(FC_CF_DEACTIVATE) || sc.equals(FC_CF_FORWARD_TO_NUMBER) + || sc.equals(FC_CFBL_ACTIVATE) || sc.equals(FC_CFBL_DEACTIVATE) + || sc.equals(FC_CFBL_FORWARD_TO_NUMBER) || sc.equals(FC_CFDA_ACTIVATE) + || sc.equals(FC_CFDA_DEACTIVATE) || sc.equals(FC_CFDA_FORWARD_TO_NUMBER)); + } + + static boolean isServiceCodeCallWaiting(String sc) { + return sc != null && sc.equals(FC_CCW); + } + + static boolean isServiceCodeThreeWayCalling(String sc) { + return sc != null && sc.equals(FC_3WC); + } + + static boolean isServiceCodeAnnoyingCalls(String sc) { + return sc != null && + (sc.equals(FC_RUAC_ACTIVATE) + || sc.equals(FC_RUAC_DEACTIVATE)); + } + + static boolean isServiceCodeCallingNumberDelivery(String sc) { + return sc != null && + (sc.equals(FC_CNIP) + || sc.equals(FC_CNIR)); + } + + static boolean isServiceCodeDoNotDisturb(String sc) { + return sc != null && + (sc.equals(FC_DND_ACTIVATE) + || sc.equals(FC_DND_DEACTIVATE)); + } + + + //***** Constructor + + FeatureCode (CDMAPhone phone) { + super(phone.getHandler().getLooper()); + this.phone = phone; + this.context = phone.getContext(); + } + + + //***** MmiCode implementation + + public State getState() { + return state; + } + + public CharSequence getMessage() { + return message; + } + + // inherited javadoc suffices + public void cancel() { + //Not used here + } + + public boolean isCancelable() { + Log.e(LOG_TAG, "isCancelable: not used in CDMA"); + return false; + } + + public boolean isUssdRequest() { + Log.e(LOG_TAG, "isUssdRequest: not used in CDMA"); + return false; + } + + /** Process a Flash Code...anything that isn't a dialing number */ + void processCode () { + Log.d(LOG_TAG, "send feature code..."); + phone.mCM.sendCDMAFeatureCode(this.poundString, + obtainMessage(EVENT_CDMA_FLASH_COMPLETED)); + } + + /** Called from CDMAPhone.handleMessage; not a Handler subclass */ + public void handleMessage (Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_SET_COMPLETE: + ar = (AsyncResult) (msg.obj); + onSetComplete(ar); + break; + case EVENT_CDMA_FLASH_COMPLETED: + ar = (AsyncResult) (msg.obj); + + if (ar.exception != null) { + state = State.FAILED; + message = context.getText(com.android.internal.R.string.fcError); + } else { + state = State.COMPLETE; + message = context.getText(com.android.internal.R.string.fcComplete); + } + phone.onFeatureCodeDone(this); + break; + } + } + + + //***** Private instance methods + + private CharSequence getScString() { + if (sc != null) { + if (isServiceCodeCallForwarding(sc)) { + return context.getText(com.android.internal.R.string.CfMmi); + } else if (isServiceCodeCallWaiting(sc)) { + return context.getText(com.android.internal.R.string.CwMmi); + } else if (sc.equals(FC_CNIP)) { + return context.getText(com.android.internal.R.string.CnipMmi); + } else if (sc.equals(FC_CNIR)) { + return context.getText(com.android.internal.R.string.CnirMmi); + } else if (isServiceCodeThreeWayCalling(sc)) { + return context.getText(com.android.internal.R.string.ThreeWCMmi); + } else if (isServiceCodeAnnoyingCalls(sc)) { + return context.getText(com.android.internal.R.string.RuacMmi); + } else if (isServiceCodeCallingNumberDelivery(sc)) { + return context.getText(com.android.internal.R.string.CndMmi); + } else if (isServiceCodeDoNotDisturb(sc)) { + return context.getText(com.android.internal.R.string.DndMmi); + } + } + + return ""; + } + + private void onSetComplete(AsyncResult ar){ + StringBuilder sb = new StringBuilder(getScString()); + sb.append("\n"); + + if (ar.exception != null) { + state = State.FAILED; + sb.append(context.getText(com.android.internal.R.string.mmiError)); + } else { + state = State.FAILED; + sb.append(context.getText(com.android.internal.R.string.mmiError)); + } + + message = sb; + phone.onFeatureCodeDone(this); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java new file mode 100644 index 0000000000000000000000000000000000000000..9d9f47958e29dd16b007c5a6c04ff67ffa9272ed --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java @@ -0,0 +1,522 @@ +/* + * 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.cdma; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; + +import android.app.ActivityManagerNative; +import android.content.Intent; +import android.content.res.Configuration; + +import static android.Manifest.permission.READ_PHONE_STATE; + +/** + * Note: this class shares common code with SimCard, consider a base class to minimize code + * duplication. + * {@hide} + */ +public final class RuimCard extends Handler implements IccCard { + static final String LOG_TAG="CDMA"; + + //***** Instance Variables + private static final boolean DBG = true; + + private CDMAPhone phone; + + private CommandsInterface.IccStatus status = null; + private boolean mDesiredPinLocked; + private boolean mDesiredFdnEnabled; + private boolean mRuimPinLocked = true; // default to locked + private boolean mRuimFdnEnabled = false; // Default to disabled. + // Will be updated when RUIM_READY. +// //***** Constants + +// // FIXME I hope this doesn't conflict with the Dialer's notifications +// Nobody is using this at the moment +// static final int NOTIFICATION_ID_ICC_STATUS = 33456; + + //***** Event Constants + + static final int EVENT_RUIM_LOCKED_OR_ABSENT = 1; + static final int EVENT_GET_RUIM_STATUS_DONE = 2; + static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; + static final int EVENT_PINPUK_DONE = 4; + static final int EVENT_REPOLL_STATUS_DONE = 5; + static final int EVENT_RUIM_READY = 6; + static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; + static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; + static final int EVENT_CHANGE_RUIM_PASSWORD_DONE = 9; + static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; + static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; + + + //***** Constructor + + RuimCard(CDMAPhone phone) { + this.phone = phone; + + phone.mCM.registerForRUIMLockedOrAbsent( + this, EVENT_RUIM_LOCKED_OR_ABSENT, null); + + phone.mCM.registerForOffOrNotAvailable( + this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + + phone.mCM.registerForRUIMReady( + this, EVENT_RUIM_READY, null); + + updateStateProperty(); + } + + //***** RuimCard implementation + + public State + getState() { + if (status == null) { + switch(phone.mCM.getRadioState()) { + /* This switch block must not return anything in + * State.isLocked() or State.ABSENT. + * If it does, handleSimStatus() may break + */ + case RADIO_OFF: + case RADIO_UNAVAILABLE: + case RUIM_NOT_READY: + return State.UNKNOWN; + case RUIM_LOCKED_OR_ABSENT: + //this should be transient-only + return State.UNKNOWN; + case RUIM_READY: + return State.READY; + case NV_READY: + case NV_NOT_READY: + return State.ABSENT; + } + } else { + switch (status) { + case ICC_ABSENT: return State.ABSENT; + case ICC_NOT_READY: return State.UNKNOWN; + case ICC_READY: return State.READY; + case ICC_PIN: return State.PIN_REQUIRED; + case ICC_PUK: return State.PUK_REQUIRED; + case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; + } + } + + Log.e(LOG_TAG, "RuimCard.getState(): case should never be reached"); + return State.UNKNOWN; + } + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForRUIMLockedOrAbsent(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + phone.mCM.unregisterForRUIMReady(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimCard finalized"); + } + + private RegistrantList absentRegistrants = new RegistrantList(); + private RegistrantList pinLockedRegistrants = new RegistrantList(); + private RegistrantList networkLockedRegistrants = new RegistrantList(); + + + public void registerForAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + absentRegistrants.add(r); + + if (getState() == State.ABSENT) { + r.notifyRegistrant(); + } + } + + public void unregisterForAbsent(Handler h) { + absentRegistrants.remove(h); + } + + public void registerForNetworkLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + networkLockedRegistrants.add(r); + + if (getState() == State.NETWORK_LOCKED) { + r.notifyRegistrant(); + } + } + + public void unregisterForNetworkLocked(Handler h) { + networkLockedRegistrants.remove(h); + } + + public void registerForLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + pinLockedRegistrants.add(r); + + if (getState().isPinLocked()) { + r.notifyRegistrant(); + } + } + + public void unregisterForLocked(Handler h) { + pinLockedRegistrants.remove(h); + } + + public void supplyPin (String pin, Message onComplete) { + phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk (String puk, String newPin, Message onComplete) { + phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPin2 (String pin2, Message onComplete) { + phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { + phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyNetworkDepersonalization (String pin, Message onComplete) { + if(DBG) log("Network Despersonalization: " + pin); + phone.mCM.supplyNetworkDepersonalization(pin, + obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public boolean getIccLockEnabled() { + return mRuimPinLocked; + } + + public boolean getIccFdnEnabled() { + return mRuimFdnEnabled; + } + + public void setIccLockEnabled (boolean enabled, + String password, Message onComplete) { + int serviceClassX; + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX; + + mDesiredPinLocked = enabled; + + phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, + enabled, password, serviceClassX, + obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); + } + + public void setIccFdnEnabled (boolean enabled, + String password, Message onComplete) { + int serviceClassX; + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX + + CommandsInterface.SERVICE_CLASS_SMS; + + mDesiredFdnEnabled = enabled; + + phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, + enabled, password, serviceClassX, + obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); + } + + public void changeIccLockPassword(String oldPassword, String newPassword, + Message onComplete) { + if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); + phone.mCM.changeIccPin(oldPassword, newPassword, + obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); + } + + public void changeIccFdnPassword(String oldPassword, String newPassword, + Message onComplete) { + if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); + phone.mCM.changeIccPin2(oldPassword, newPassword, + obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); + } + + public String getServiceProviderName() { + return phone.mRuimRecords.getServiceProviderName(); + } + + //***** Handler implementation + @Override + public void handleMessage(Message msg){ + AsyncResult ar; + int serviceClassX; + + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX; + + switch (msg.what) { + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); + status = null; + updateStateProperty(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null); + break; + case EVENT_RUIM_READY: + Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received"); + //TODO: put facility read in SIM_READY now, maybe in REG_NW + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); + phone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + phone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); + break; + case EVENT_RUIM_LOCKED_OR_ABSENT: + Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received"); + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); + phone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + break; + case EVENT_GET_RUIM_STATUS_DONE: + Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received"); + ar = (AsyncResult)msg.obj; + + getRuimStatusDone(ar); + break; + case EVENT_PINPUK_DONE: + Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received"); + // a PIN/PUK/PIN2/PUK2/Network Personalization + // request has completed. ar.userObj is the response Message + // Repoll before returning + ar = (AsyncResult)msg.obj; + // TODO should abstract these exceptions + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + phone.mCM.getIccStatus( + obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); + break; + case EVENT_REPOLL_STATUS_DONE: + Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received"); + // Finished repolling status after PIN operation + // ar.userObj is the response messaeg + // ar.userObj.obj is already an AsyncResult with an + // appropriate exception filled in if applicable + + ar = (AsyncResult)msg.obj; + getRuimStatusDone(ar); + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_QUERY_FACILITY_LOCK_DONE: + Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received"); + ar = (AsyncResult)msg.obj; + onQueryFacilityLock(ar); + break; + case EVENT_QUERY_FACILITY_FDN_DONE: + Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received"); + ar = (AsyncResult)msg.obj; + onQueryFdnEnabled(ar); + break; + case EVENT_CHANGE_FACILITY_LOCK_DONE: + Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received"); + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + mRuimPinLocked = mDesiredPinLocked; + if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + + "mRuimPinLocked= " + mRuimPinLocked); + } else { + Log.e(LOG_TAG, "Error change facility lock with exception " + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_CHANGE_FACILITY_FDN_DONE: + Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received"); + ar = (AsyncResult)msg.obj; + + if (ar.exception == null) { + mRuimFdnEnabled = mDesiredFdnEnabled; + if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + + "mRuimFdnEnabled=" + mRuimFdnEnabled); + } else { + Log.e(LOG_TAG, "Error change facility fdn with exception " + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_CHANGE_RUIM_PASSWORD_DONE: + Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received"); + ar = (AsyncResult)msg.obj; + if(ar.exception != null) { + Log.e(LOG_TAG, "Error in change sim password with exception" + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + default: + Log.e(LOG_TAG, "[CdmaRuimCard] Unknown Event " + msg.what); + } + } + + //***** Private methods + + /** + * Interpret EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFacilityLock(AsyncResult ar) { + if(ar.exception != null) { + if (DBG) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mRuimPinLocked = (0!=ints[0]); + if(DBG) log("Query facility lock : " + mRuimPinLocked); + } else { + Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response"); + } + } + + /** + * Interpret EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFdnEnabled(AsyncResult ar) { + if(ar.exception != null) { + if(DBG) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mRuimFdnEnabled = (0!=ints[0]); + if(DBG) log("Query facility lock : " + mRuimFdnEnabled); + } else { + Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response"); + } + } + + private void + getRuimStatusDone(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG,"Error getting SIM status. " + + "RIL_REQUEST_GET_SIM_STATUS should " + + "never return an error", ar.exception); + return; + } + + CommandsInterface.IccStatus newStatus + = (CommandsInterface.IccStatus) ar.result; + + handleRuimStatus(newStatus); + } + + private void + handleRuimStatus(CommandsInterface.IccStatus newStatus) { + boolean transitionedIntoPinLocked; + boolean transitionedIntoAbsent; + boolean transitionedIntoNetworkLocked; + + RuimCard.State oldState, newState; + + oldState = getState(); + status = newStatus; + newState = getState(); + + updateStateProperty(); + + transitionedIntoPinLocked = ( + (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED) + || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED)); + transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT); + transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED + && newState == State.NETWORK_LOCKED); + + if (transitionedIntoPinLocked) { + if(DBG) log("Notify RUIM pin or puk locked."); + pinLockedRegistrants.notifyRegistrants(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, + (newState == State.PIN_REQUIRED) ? + INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); + } else if (transitionedIntoAbsent) { + if(DBG) log("Notify RUIM missing."); + absentRegistrants.notifyRegistrants(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null); + } else if (transitionedIntoNetworkLocked) { + if(DBG) log("Notify RUIM network locked."); + networkLockedRegistrants.notifyRegistrants(); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, + INTENT_VALUE_LOCKED_NETWORK); + } + } + + public void broadcastRuimStateChangedIntent(String value, String reason) { + Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName()); + intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value); + intent.putExtra(RuimCard.INTENT_KEY_LOCKED_REASON, reason); + if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value + + " reason " + reason); + ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); + } + + public void updateImsiConfiguration(String imsi) { + if (imsi.length() >= 6) { + Configuration config = new Configuration(); + config.mcc = ((imsi.charAt(0)-'0')*100) + + ((imsi.charAt(1)-'0')*10) + + (imsi.charAt(2)-'0'); + config.mnc = ((imsi.charAt(3)-'0')*100) + + ((imsi.charAt(4)-'0')*10) + + (imsi.charAt(5)-'0'); + try { + ActivityManagerNative.getDefault().updateConfiguration(config); + } catch (RemoteException e) { + } + } + } + + private void + updateStateProperty() { + phone.setSystemProperty( + TelephonyProperties.PROPERTY_SIM_STATE, + getState().toString()); + } + + private void log(String msg) { + Log.d(LOG_TAG, "[RuimCard] " + msg); + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..9de6c42f45d7e5527a904a99c0aaa9cb73f6d874 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.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 com.android.internal.telephony.cdma; + +import android.os.*; +import android.util.Log; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccFileTypeMismatch; +import com.android.internal.telephony.IccIoResult; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; + +/** + * {@hide} + */ +public final class RuimFileHandler extends IccFileHandler { + static final String LOG_TAG = "CDMA"; + + //***** Instance Variables + + //***** Constructor + RuimFileHandler(CDMAPhone phone) { + super(phone); + } + + public void dispose() { + } + + protected void finalize() { + Log.d(LOG_TAG, "RuimFileHandler finalized"); + } + + //***** Overridden from IccFileHandler + + @Override + public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, + int length, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, + onLoaded); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, "img", 0, 0, + GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response); + } + + @Override + public void handleMessage(Message msg) { + + super.handleMessage(msg); + } + + protected String getEFPath(int efid) { + // TODO(): Implement for CDMA EFs. + return getCommonIccEFPath(efid); + } + + protected void logd(String msg) { + Log.d(LOG_TAG, "[RuimFileHandler] " + msg); + } + + protected void loge(String msg) { + Log.e(LOG_TAG, "[RuimFileHandler] " + msg); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java new file mode 100644 index 0000000000000000000000000000000000000000..78e89d56cb926860c6b7bab127a1acd30549d6c7 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java @@ -0,0 +1,101 @@ +/* +** 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.internal.telephony.cdma; + +import android.content.pm.PackageManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ServiceManager; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; +import java.util.List; + +/** + * RuimPhoneBookInterfaceManager to provide an inter-process communication to + * access ADN-like SIM records. + */ + + +public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { + static final String LOG_TAG = "CDMA"; + + + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch(msg.what) { + default: + mBaseHandler.handleMessage(msg); + break; + } + } + }; + + public RuimPhoneBookInterfaceManager(CDMAPhone phone) { + super(phone); + adnCache = phone.mRuimRecords.getAdnCache(); + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy + } + + public void dispose() { + super.dispose(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimPhoneBookInterfaceManager finalized"); + } + + public int[] getAdnRecordsSize(int efid) { + if (DBG) logd("getAdnRecordsSize: efid=" + efid); + synchronized(mLock) { + checkThread(); + recordSize = new int[3]; + + //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling + Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE); + + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to load from the RUIM"); + } + } + + return recordSize; + } + + protected void logd(String msg) { + Log.d(LOG_TAG, "[RuimPbInterfaceManager] " + msg); + } + + protected void loge(String msg) { + Log.e(LOG_TAG, "[RuimPbInterfaceManager] " + msg); + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java new file mode 100644 index 0000000000000000000000000000000000000000..b18a3f18ffa9d712afd454eb2fe845a56e341543 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -0,0 +1,399 @@ +/* + * 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.cdma; + +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.util.Log; + +import static com.android.internal.telephony.TelephonyProperties.*; +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.AdnRecordLoader; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.cdma.RuimCard; +import com.android.internal.telephony.gsm.MccTable; + +// can't be used since VoiceMailConstants is not public +//import com.android.internal.telephony.gsm.VoiceMailConstants; +import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccRecords; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + + +/** + * {@hide} + */ +public final class RuimRecords extends IccRecords { + static final String LOG_TAG = "CDMA"; + + private static final boolean DBG = true; + + //***** Instance Variables + String imsi_m; + String mdn = null; // My mobile number + String h_sid; + String h_nid; + String min2_min1; // 10 digit MIN value MIN2+MIN1 NEWRIL:TODO currently unused + + // is not initialized + + //***** Event Constants + + private static final int EVENT_RUIM_READY = 1; + private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2; + private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4; + private static final int EVENT_GET_ICCID_DONE = 5; + private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10; + private static final int EVENT_UPDATE_DONE = 14; + private static final int EVENT_GET_SST_DONE = 17; + private static final int EVENT_GET_ALL_SMS_DONE = 18; + private static final int EVENT_MARK_SMS_READ_DONE = 19; + + private static final int EVENT_SMS_ON_RUIM = 21; + private static final int EVENT_GET_SMS_DONE = 22; + + private static final int EVENT_RUIM_REFRESH = 31; + + //***** Constructor + + RuimRecords(CDMAPhone p) { + super(p); + + adnCache = new AdnRecordCache(phone); + + recordsRequested = false; // No load request is made till SIM ready + + // recordsToLoad is set to 0 because no requests are made yet + recordsToLoad = 0; + + + p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + // NOTE the EVENT_SMS_ON_RUIM is not registered + p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null); + + // Start off by setting empty state + onRadioOffOrNotAvailable(); + + } + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForRUIMReady(this); + phone.mCM.unregisterForOffOrNotAvailable( this); + phone.mCM.unSetOnIccRefresh(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimRecords finalized"); + } + + protected void onRadioOffOrNotAvailable() { + countVoiceMessages = 0; + mncLength = 0; + iccid = null; + + adnCache.reset(); + + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null); + + // recordsRequested is set to false indicating that the SIM + // read requests made so far are not valid. This is set to + // true only when fresh set of read requests are made. + recordsRequested = false; + } + + //***** Public Methods + + /** Returns null if RUIM is not yet ready */ + public String getIMSI_M() { + return imsi_m; + } + + public String getMdnNumber() { + return mdn; + } + + public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){ + // In CDMA this is Operator/OEM dependent + AsyncResult.forMessage((onComplete)).exception = + new IccException("setVoiceMailNumber not implemented"); + onComplete.sendToTarget(); + Log.e(LOG_TAG, "method setVoiceMailNumber is not implemented"); + } + + /** + * Called by CCAT Service when REFRESH is received. + * @param fileChanged indicates whether any files changed + * @param fileList if non-null, a list of EF files that changed + */ + public void onRefresh(boolean fileChanged, int[] fileList) { + if (fileChanged) { + // A future optimization would be to inspect fileList and + // only reload those files that we care about. For now, + // just re-fetch all RUIM records that we cache. + fetchRuimRecords(); + } + } + + /** Returns the 5 or 6 digit MCC/MNC of the operator that + * provided the RUIM card. Returns null of RUIM is not yet ready + */ + String getRUIMOperatorNumeric() { + if (imsi_m == null) { + return null; + } + + if (mncLength != 0) { + // Length = length of MCC + length of MNC + // TODO: change spec name + // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3) + return imsi_m.substring(0, 3 + mncLength); + } + + // Guess the MNC length based on the MCC if we don't + // have a valid value in ef[ad] + + int mcc; + + mcc = Integer.parseInt(imsi_m.substring(0,3)); + + return imsi_m.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); + } + + //***** Overridden from Handler + public void handleMessage(Message msg) { + AsyncResult ar; + + byte data[]; + + boolean isRecordLoadResponse = false; + + try { switch (msg.what) { + case EVENT_RUIM_READY: + onRuimReady(); + break; + + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + onRadioOffOrNotAvailable(); + break; + + case EVENT_GET_DEVICE_IDENTITY_DONE: + Log.d(LOG_TAG, "Event EVENT_GET_DEVICE_IDENTITY_DONE Received"); + break; + + /* IO events */ + + case EVENT_GET_CDMA_SUBSCRIPTION_DONE: + ar = (AsyncResult)msg.obj; + String localTemp[] = (String[])ar.result; + if (ar.exception != null) { + break; + } + + mdn = localTemp[0]; + h_sid = localTemp[1]; + h_nid = localTemp[2]; + if (localTemp.length >= 3) { // NEWRIL:TODO remove when new ril always returns min2_min1 + min2_min1 = localTemp[3]; + } + + Log.d(LOG_TAG, "MDN: " + mdn); + + break; + + case EVENT_GET_ICCID_DONE: + isRecordLoadResponse = true; + + ar = (AsyncResult)msg.obj; + data = (byte[])ar.result; + + if (ar.exception != null) { + break; + } + + iccid = IccUtils.bcdToString(data, 0, data.length); + + Log.d(LOG_TAG, "iccid: " + iccid); + + break; + + case EVENT_UPDATE_DONE: + ar = (AsyncResult)msg.obj; + if (ar.exception != null) { + Log.i(LOG_TAG, "RuimRecords update failed", ar.exception); + } + break; + + case EVENT_GET_ALL_SMS_DONE: + case EVENT_MARK_SMS_READ_DONE: + case EVENT_SMS_ON_RUIM: + case EVENT_GET_SMS_DONE: + Log.w(LOG_TAG, "Event not supported: " + msg.what); + break; + + // TODO: probably EF_CST should be read instead + case EVENT_GET_SST_DONE: + Log.d(LOG_TAG, "Event EVENT_GET_SST_DONE Received"); + break; + + case EVENT_RUIM_REFRESH: + isRecordLoadResponse = false; + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + handleRuimRefresh((int[])(ar.result)); + } + break; + + }}catch (RuntimeException exc) { + // I don't want these exceptions to be fatal + Log.w(LOG_TAG, "Exception parsing RUIM record", exc); + } finally { + // Count up record load responses even if they are fails + if (isRecordLoadResponse) { + onRecordLoaded(); + } + } + } + + protected void onRecordLoaded() { + // One record loaded successfully or failed, In either case + // we need to update the recordsToLoad count + recordsToLoad -= 1; + + if (recordsToLoad == 0 && recordsRequested == true) { + onAllRecordsLoaded(); + } else if (recordsToLoad < 0) { + Log.e(LOG_TAG, "RuimRecords: recordsToLoad <0, programmer error suspected"); + recordsToLoad = 0; + } + } + + protected void onAllRecordsLoaded() { + Log.d(LOG_TAG, "RuimRecords: record load complete"); + + // Further records that can be inserted are Operator/OEM dependent + + recordsLoadedRegistrants.notifyRegistrants( + new AsyncResult(null, null, null)); + ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + RuimCard.INTENT_VALUE_ICC_LOADED, null); + } + + + //***** Private Methods + + private void onRuimReady() { + /* broadcast intent ICC_READY here so that we can make sure + READY is sent before IMSI ready + */ + + ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + RuimCard.INTENT_VALUE_ICC_READY, null); + + fetchRuimRecords(); + + phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); + + } + + private void fetchRuimRecords() { + recordsRequested = true; + + Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad); + + phone.getIccFileHandler().loadEFTransparent(EF_ICCID, + obtainMessage(EVENT_GET_ICCID_DONE)); + recordsToLoad++; + + // Further records that can be inserted are Operator/OEM dependent + } + + @Override + protected int getDisplayRule(String plmn) { + // TODO together with spn + return 0; + } + + @Override + public void setVoiceMessageWaiting(int line, int countWaiting) { + if (line != 1) { + // only profile 1 is supported + return; + } + + // range check + if (countWaiting < 0) { + countWaiting = -1; + } else if (countWaiting > 0xff) { + // C.S0015-B v2, 4.5.12 + // range: 0-99 + countWaiting = 0xff; + } + countVoiceMessages = countWaiting; + + ((CDMAPhone) phone).notifyMessageWaitingIndicator(); + } + + private void handleRuimRefresh(int[] result) { + if (result == null || result.length == 0) { + if (DBG) log("handleRuimRefresh without input"); + return; + } + + switch ((result[0])) { + case CommandsInterface.SIM_REFRESH_FILE_UPDATED: + if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED"); + adnCache.reset(); + fetchRuimRecords(); + break; + case CommandsInterface.SIM_REFRESH_INIT: + if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT"); + // need to reload all files (that we care about) + fetchRuimRecords(); + break; + case CommandsInterface.SIM_REFRESH_RESET: + if (DBG) log("handleRuimRefresh 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), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + break; + default: + // unknown refresh operation + if (DBG) log("handleRuimRefresh with unknown operation"); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[RuimRecords] " + s); + } + +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java new file mode 100644 index 0000000000000000000000000000000000000000..9439359fe735a9b76355a2b9fa9ca1e80f9ad2f7 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.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 com.android.internal.telephony.cdma; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.SmsRawData; + +import java.util.ArrayList; +import java.util.List; + +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; + +/** + * RuimSmsInterfaceManager to provide an inter-process communication to + * access Sms in Ruim. + */ +public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { + static final String LOG_TAG = "CDMA"; + static final boolean DBG = true; + + private final Object mLock = new Object(); + private boolean mSuccess; + private List mSms; + + private static final int EVENT_LOAD_DONE = 1; + private static final int EVENT_UPDATE_DONE = 2; + + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_UPDATE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + mSuccess = (ar.exception == null); + mLock.notifyAll(); + } + break; + case EVENT_LOAD_DONE: + ar = (AsyncResult)msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + mSms = (List) + buildValidRawData((ArrayList) ar.result); + } else { + if(DBG) log("Cannot load Sms records"); + if (mSms != null) + mSms.clear(); + } + mLock.notifyAll(); + } + break; + } + } + }; + + public RuimSmsInterfaceManager(CDMAPhone phone) { + super(phone); + mDispatcher = new CdmaSMSDispatcher(phone); + } + + public void dispose() { + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimSmsInterfaceManager finalized"); + } + + /** + * Update the specified message on the RUIM. + * + * @param index record index of message to update + * @param status new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) + * @param pdu the raw PDU to store + * @return success or not + * + */ + public boolean + updateMessageOnIccEf(int index, int status, byte[] pdu) { + if (DBG) log("updateMessageOnIccEf: index=" + index + + " status=" + status + " ==> " + + "("+ pdu + ")"); + enforceReceiveAndSend("Updating message on RUIM"); + synchronized(mLock) { + mSuccess = false; + Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); + + if (status == STATUS_ON_ICC_FREE) { + // Special case FREE: call deleteSmsOnRuim instead of + // manipulating the RUIM record + mPhone.mCM.deleteSmsOnRuim(index, response); + } else { + byte[] record = makeSmsRecordData(status, pdu); + mPhone.getIccFileHandler().updateEFLinearFixed( + IccConstants.EF_SMS, index, record, null, response); + } + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to update by index"); + } + } + return mSuccess; + } + + /** + * Copy a raw SMS PDU to the RUIM. + * + * @param pdu the raw PDU to store + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) + * @return success or not + * + */ + public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { + //NOTE smsc not used in RUIM + if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + + "pdu=("+ pdu + ")"); + enforceReceiveAndSend("Copying message to RUIM"); + synchronized(mLock) { + mSuccess = false; + Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); + + mPhone.mCM.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu), + response); + + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to update by index"); + } + } + return mSuccess; + } + + /** + * Retrieves all messages currently stored on RUIM. + */ + public List getAllMessagesFromIccEf() { + if (DBG) log("getAllMessagesFromEF"); + + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.RECEIVE_SMS", + "Reading messages from RUIM"); + synchronized(mLock) { + Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); + mPhone.getIccFileHandler().loadEFLinearFixedAll(IccConstants.EF_SMS, response); + + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to load from the RUIM"); + } + } + return mSms; + } + + protected void log(String msg) { + Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg); + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..343a22e54010843abf990ec3c68c792de80af04a --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -0,0 +1,854 @@ +/* + * 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.cdma; + +import android.os.Parcel; +import android.text.format.Time; +import android.util.Config; +import android.util.Log; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.cdma.sms.BearerData; +import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; +import com.android.internal.telephony.cdma.sms.SmsEnvelope; +import com.android.internal.telephony.cdma.sms.UserData; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Random; + +/** + * TODO(cleanup): these constants are disturbing... are they not just + * different interpretations on one number? And if we did not have + * terrible class name overlap, they would not need to be directly + * imported like this. The class in this file could just as well be + * named CdmaSmsMessage, could it not? + */ + +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; +import static android.telephony.SmsMessage.MessageClass; + +/** + * TODO(cleanup): internally returning null in many places makes + * debugging very hard (among many other reasons) and should be made + * more meaningful (replaced with execptions for example). Null + * returns should only occur at the very outside of the module/class + * scope. + */ + +/** + * A Short Message Service message. + * + */ +public class SmsMessage extends SmsMessageBase { + static final String LOG_TAG = "CDMA"; + + /** + * Status of a previously submitted SMS. + * This field applies to SMS Delivery Acknowledge messages. 0 indicates success; + * Here, the error class is defined by the bits from 9-8, the status code by the bits from 7-0. + * See C.S0015-B, v2.0, 4.5.21 for a detailed description of possible values. + */ + private int status; + + /** The next message ID for the BearerData. Shall be a random value on first use. + * (See C.S0015-B, v2.0, 4.3.1.5) + */ + private static int nextMessageId = 0; + + /** Specifies if this is the first SMS message submit */ + private static boolean firstSMS = true; + + /** Specifies if a return of an acknowledgment is requested for send SMS */ + private static final int RETURN_NO_ACK = 0; + private static final int RETURN_ACK = 1; + + private SmsEnvelope mEnvelope; + private BearerData mBearerData; + + public static class SubmitPdu extends SubmitPduBase { + } + + /** + * Create an SmsMessage from a raw PDU. + * Note: In CDMA the PDU is just a byte representation of the received Sms. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + SmsMessage msg = new SmsMessage(); + + try { + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCMT(String[] lines) { + Log.w(LOG_TAG, "newFromCMT: is not supported in CDMA mode."); + return null; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCMTI(String line) { + Log.w(LOG_TAG, "newFromCMTI: is not supported in CDMA mode."); + return null; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCDS(String line) { + Log.w(LOG_TAG, "newFromCDS: is not supported in CDMA mode."); + return null; + } + + /** + * Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp. + * Note: Only primitive fields are set. + */ + public static SmsMessage newFromParcel(Parcel p) { + // Note: Parcel.readByte actually reads one Int and masks to byte + SmsMessage msg = new SmsMessage(); + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress addr = new CdmaSmsAddress(); + byte[] data; + byte count; + int countInt; + int addressDigitMode; + + //currently not supported by the modem-lib: env.mMessageType + env.teleService = p.readInt(); //p_cur->uTeleserviceID + + if (0 != p.readByte()) { //p_cur->bIsServicePresent + env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST; + } + else { + if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) { + // assume type ACK + env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE; + } else { + env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; + } + } + env.serviceCategory = p.readInt(); //p_cur->uServicecategory + + // address + addressDigitMode = p.readInt(); + addr.digitMode = (byte) (0xFF & addressDigitMode); //p_cur->sAddress.digit_mode + addr.numberMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_mode + addr.ton = p.readInt(); //p_cur->sAddress.number_type + addr.numberPlan = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_plan + count = p.readByte(); //p_cur->sAddress.number_of_digits + addr.numberOfDigits = count; + data = new byte[count]; + //p_cur->sAddress.digits[digitCount] + for (int index=0; index < count; index++) { + data[index] = p.readByte(); + + // convert the value if it is 4-bit DTMF to 8 bit + if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) { + data[index] = msg.convertDtmfToAscii(data[index]); + } + } + + addr.origBytes = data; + + // ignore subaddress + p.readInt(); //p_cur->sSubAddress.subaddressType + p.readInt(); //p_cur->sSubAddress.odd + count = p.readByte(); //p_cur->sSubAddress.number_of_digits + //p_cur->sSubAddress.digits[digitCount] : + for (int index=0; index < count; index++) { + p.readByte(); + } + + /* currently not supported by the modem-lib: + env.bearerReply + env.replySeqNo + env.errorClass + env.causeCode + */ + + // bearer data + countInt = p.readInt(); //p_cur->uBearerDataLen + if (countInt >0) { + data = new byte[countInt]; + //p_cur->aBearerData[digitCount] : + for (int index=0; index < countInt; index++) { + data[index] = p.readByte(); + } + env.bearerData = data; + // BD gets further decoded when accessed in SMSDispatcher + } + + // link the the filled objects to the SMS + env.origAddress = addr; + msg.originatingAddress = addr; + msg.mEnvelope = env; + + // create byte stream representation for transportation through the layers. + msg.createPdu(); + + return msg; + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + try { + SmsMessage msg = new SmsMessage(); + + msg.indexOnIcc = index; + + // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, + // or STORED_UNSENT + // See 3GPP2 C.S0023 3.4.27 + if ((data[0] & 1) == 0) { + Log.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record"); + return null; + } else { + msg.statusOnIcc = data[0] & 0x07; + } + + // Second byte is the MSG_LEN, length of the message + // See 3GPP2 C.S0023 3.4.27 + int size = data[1]; + + // Note: Data may include trailing FF's. That's OK; message + // should still parse correctly. + byte[] pdu = new byte[size]; + System.arraycopy(data, 2, pdu, 0, size); + // the message has to be parsed before it can be displayed + // see gsm.SmsMessage + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static int getTPLayerLengthForPDU(String pdu) { + Log.w(LOG_TAG, "getTPLayerLengthForPDU: is not supported in CDMA mode."); + return 0; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddr Service Centre address. Null means use default. + * @param destAddr Address of the recipient. + * @param message String representation of the message payload. + * @param statusReportRequested Indicates whether a report is requested for this message. + * @param headerData Array containing the data for the User Data Header, preceded + * by the Element Identifiers. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddr, + String destAddr, String message, + boolean statusReportRequested, byte[] headerData) { + /** + * TODO(cleanup): why does this method take an scAddr input + * and do nothing with it? GSM allows us to specify a SC (eg, + * when responding to an SMS that explicitly requests the + * response is sent to a specific SC), or pass null to use the + * default value. Is there no similar notion in CDMA? Or do + * we just not have it hooked up? + */ + + if (message == null || destAddr == null) { + return null; + } + + UserData uData = new UserData(); + uData.payloadStr = message; + if(headerData != null) { + /** + * TODO(cleanup): we force the outside to deal with _all_ + * of the raw details of properly constructing serialized + * headers, unserialze here, and then promptly reserialze + * during encoding -- rather undesirable. + */ + uData.userDataHeader = SmsHeader.parse(headerData); + } + + return privateGetSubmitPdu(destAddr, statusReportRequested, uData, (headerData == null)); + } + + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested) { + return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param destinationPort the port to deliver the message to at the + * destination + * @param data the data for the message + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destAddr, short destinationPort, byte[] data, + boolean statusReportRequested) { + + /** + * TODO(cleanup): if we had properly exposed SmsHeader + * information, this mess of many getSubmitPdu public + * interface methods that currently pollute the api could have + * been much more cleanly collapsed into one. + */ + + /** + * TODO(cleanup): header serialization should be put somewhere + * canonical to allow proper debugging and reuse. + */ + byte[] destPort = new byte[4]; + destPort[0] = (byte) ((destinationPort >> 8) & 0xFF); // MSB of destination port + destPort[1] = (byte) (destinationPort & 0xFF); // LSB of destination port + destPort[2] = 0x00; // MSB of originating port + destPort[3] = 0x00; // LSB of originating port + SmsHeader smsHeader = new SmsHeader(); + smsHeader.add( + new SmsHeader.Element(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT, destPort)); + smsHeader.nbrOfHeaders = smsHeader.getElements().size(); + + UserData uData = new UserData(); + uData.userDataHeader = smsHeader; + uData.msgEncoding = UserData.ENCODING_OCTET; + uData.msgEncodingSet = true; + uData.payload = data; + + return privateGetSubmitPdu(destAddr, statusReportRequested, uData, true); + } + + static class PduParser { + + PduParser() { + } + + /** + * Parses an SC timestamp and returns a currentTimeMillis()-style + * timestamp + */ + static long getSCTimestampMillis(byte[] timestamp) { + // TP-Service-Centre-Time-Stamp + int year = IccUtils.beBcdByteToInt(timestamp[0]); + int month = IccUtils.beBcdByteToInt(timestamp[1]); + int day = IccUtils.beBcdByteToInt(timestamp[2]); + int hour = IccUtils.beBcdByteToInt(timestamp[3]); + int minute = IccUtils.beBcdByteToInt(timestamp[4]); + int second = IccUtils.beBcdByteToInt(timestamp[5]); + + Time time = new Time(Time.TIMEZONE_UTC); + + // C.S0015-B v2.0, 4.5.4: range is 1996-2095 + time.year = year >= 96 ? year + 1900 : year + 2000; + time.month = month - 1; + time.monthDay = day; + time.hour = hour; + time.minute = minute; + time.second = second; + + return time.toMillis(true); + } + + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public int getProtocolIdentifier() { + Log.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode."); + // (3GPP TS 23.040): "no interworking, but SME to SME protocol": + return 0; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isReplace() { + Log.w(LOG_TAG, "isReplace: is not supported in CDMA mode."); + return false; + } + + /** + * {@inheritDoc} + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isCphsMwiMessage() { + Log.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode."); + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMWIClearMessage() { + if ((mBearerData != null) && (0 == mBearerData.numberOfMessages)) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMWISetMessage() { + if ((mBearerData != null) && (mBearerData.numberOfMessages >0)) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMwiDontStore() { + if ((mBearerData != null) && (mBearerData.numberOfMessages >0) + && (null == mBearerData.userData)) { + return true; + } + return false; + } + + /** + * Returns the status for a previously submitted message. + * For not interfering with status codes from GSM, this status code is + * shifted to the bits 31-16. + */ + public int getStatus() { + return(status<<16); + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isStatusReportMessage() { + Log.w(LOG_TAG, "isStatusReportMessage: is not supported in CDMA mode."); + return false; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isReplyPathPresent() { + Log.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode."); + return false; + } + + /** + * Returns the teleservice type of the message. + * @return the teleservice: + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP} + */ + public int getTeleService() { + return mEnvelope.teleService; + } + + /** + * Decodes pdu to an empty SMS object. + * In the CDMA case the pdu is just an internal byte stream representation + * of the SMS Java-object. + * @see #createPdu() + */ + private void parsePdu(byte[] pdu) { + ByteArrayInputStream bais = new ByteArrayInputStream(pdu); + DataInputStream dis = new DataInputStream(new BufferedInputStream(bais)); + byte length; + int bearerDataLength; + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress addr = new CdmaSmsAddress(); + + try { + env.messageType = dis.readInt(); + env.teleService = dis.readInt(); + env.serviceCategory = dis.readInt(); + + addr.digitMode = dis.readByte(); + addr.numberMode = dis.readByte(); + addr.ton = dis.readByte(); + addr.numberPlan = dis.readByte(); + + length = dis.readByte(); + addr.numberOfDigits = length; + addr.origBytes = new byte[length]; + dis.read(addr.origBytes, 0, length); // digits + + env.bearerReply = dis.readInt(); + // CauseCode values: + env.replySeqNo = dis.readByte(); + env.errorClass = dis.readByte(); + env.causeCode = dis.readByte(); + + //encoded BearerData: + bearerDataLength = dis.readInt(); + env.bearerData = new byte[bearerDataLength]; + dis.read(env.bearerData, 0, bearerDataLength); + dis.close(); + } catch (Exception ex) { + Log.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex); + } + + // link the filled objects to this SMS + originatingAddress = addr; + env.origAddress = addr; + mEnvelope = env; + + parseSms(); + } + + /** + * Parses a SMS message from its BearerData stream. (mobile-terminated only) + */ + protected void parseSms() { + mBearerData = BearerData.decode(mEnvelope.bearerData); + messageRef = mBearerData.messageId; + + // TP-Message-Type-Indicator + // (See 3GPP2 C.S0015-B, v2, 4.5.1) + int messageType = mBearerData.messageType; + + switch (messageType) { + case BearerData.MESSAGE_TYPE_USER_ACK: + case BearerData.MESSAGE_TYPE_READ_ACK: + case BearerData.MESSAGE_TYPE_DELIVER: + // Deliver (mobile-terminated only) + parseSmsDeliver(); + break; + case BearerData.MESSAGE_TYPE_DELIVERY_ACK: + parseSmsDeliveryAck(); + break; + + default: + // the rest of these + throw new RuntimeException("Unsupported message type: " + messageType); + } + } + + /** + * TODO(cleanup): why are there two nearly identical functions + * below? More rubbish... + */ + + /** + * Parses a SMS-DELIVER message. (mobile-terminated only) + * See 3GPP2 C.S0015-B, v2, 4.4.1 + */ + private void parseSmsDeliver() { + if (originatingAddress != null) { + originatingAddress.address = new String(originatingAddress.origBytes); + if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + + originatingAddress.address); + } + + if (mBearerData.timeStamp != null) { + scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp); + } + + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); + + parseUserData(mBearerData.userData); + } + + /** + * Parses a SMS-DELIVER message. (mobile-terminated only) + * See 3GPP2 C.S0015-B, v2, 4.4.1 + */ + private void parseSmsDeliveryAck() { + if (originatingAddress != null) { + originatingAddress.address = new String(originatingAddress.origBytes); + if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + + originatingAddress.address); + } + + if (mBearerData.timeStamp != null) { + scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp); + } + + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); + + if (mBearerData.errorClass != BearerData.ERROR_UNDEFINED) { + status = mBearerData.errorClass << 8; + status |= mBearerData.messageStatus; + } + + parseUserData(mBearerData.userData); + } + + /** + * Copy parsed user data out from internal datastructures. + */ + private void parseUserData(UserData uData) { + if (uData == null) { + return; + } + + userData = uData.payload; + userDataHeader = uData.userDataHeader; + messageBody = uData.payloadStr; + + if (messageBody != null) { + if (Config.LOGV) Log.v(LOG_TAG, "SMS message body: '" + messageBody + "'"); + parseMessageBody(); + } else if ((userData != null) && (Config.LOGV)) { + Log.v(LOG_TAG, "SMS payload: '" + IccUtils.bytesToHexString(userData) + "'"); + } + } + + /** + * {@inheritDoc} + */ + public MessageClass getMessageClass() { + if (BearerData.DISPLAY_MODE_IMMEDIATE == mBearerData.displayMode ) { + return MessageClass.CLASS_0; + } else { + return MessageClass.UNKNOWN; + } + } + + private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) { + // see C.S0015-B, v2.0, 3.4.3.3 + CdmaSmsAddress addr = new CdmaSmsAddress(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; + try { + addr.origBytes = addrStr.getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException ex) { + Log.e(LOG_TAG, "CDMA address parsing failed: " + ex); + return null; + } + addr.numberOfDigits = (byte)addr.origBytes.length; + addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; + addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY; + addr.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP; + return addr; + } + + /** + * Set the nextMessageId to a random value between 0 and 65536 + * See C.S0015-B, v2.0, 4.3.1.5 + */ + private static void setNextMessageId() { + // Message ID, modulo 65536 + if(firstSMS) { + Random generator = new Random(); + nextMessageId = generator.nextInt(65536); + firstSMS = false; + } else { + nextMessageId = ++nextMessageId & 0xFFFF; + } + } + + /** + * Creates BearerData and Envelope from parameters for a Submit SMS. + * @return byte stream for SubmitPdu. + */ + private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested, + UserData userData, boolean useNewId) { + + /** + * TODO(cleanup): give this function a more meaningful name. + */ + + CdmaSmsAddress destAddr = parseCdmaSmsAddr(destAddrStr); + if (destAddr == null) return null; + + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT; + + if (useNewId) setNextMessageId(); + bearerData.messageId = nextMessageId; + + bearerData.deliveryAckReq = statusReportRequested; + bearerData.userAckReq = false; + bearerData.readAckReq = false; + bearerData.reportReq = false; + + bearerData.userData = userData; + bearerData.hasUserDataHeader = (userData.userDataHeader != null); + + byte[] encodedBearerData = BearerData.encode(bearerData); + if (encodedBearerData == null) return null; + + SmsEnvelope envelope = new SmsEnvelope(); + envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; + envelope.teleService = SmsEnvelope.TELESERVICE_WMT; + envelope.destAddress = destAddr; + envelope.bearerReply = RETURN_ACK; + envelope.bearerData = encodedBearerData; + + /** + * TODO(cleanup): envelope looks to be a pointless class, get + * rid of it. Also -- most of the envelope fields set here + * are ignored, why? + */ + + try { + /** + * TODO(cleanup): reference a spec and get rid of the ugly comments + */ + ByteArrayOutputStream baos = new ByteArrayOutputStream(100); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeInt(envelope.teleService); + dos.writeInt(0); //servicePresent + dos.writeInt(0); //serviceCategory + dos.write(destAddr.digitMode); + dos.write(destAddr.numberMode); + dos.write(destAddr.ton); // number_type + dos.write(destAddr.numberPlan); + dos.write(destAddr.numberOfDigits); + dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits + // Subaddress is not supported. + dos.write(0); //subaddressType + dos.write(0); //subaddr_odd + dos.write(0); //subaddr_nbr_of_digits + dos.write(encodedBearerData.length); + dos.write(encodedBearerData, 0, encodedBearerData.length); + dos.close(); + + SubmitPdu pdu = new SubmitPdu(); + pdu.encodedMessage = baos.toByteArray(); + pdu.encodedScAddress = null; + return pdu; + } catch(IOException ex) { + Log.e(LOG_TAG, "creating SubmitPdu failed: " + ex); + } + return null; + } + + /** + * Creates byte array (pseudo pdu) from SMS object. + * Note: Do not call this method more than once per object! + */ + private void createPdu() { + SmsEnvelope env = mEnvelope; + CdmaSmsAddress addr = env.origAddress; + ByteArrayOutputStream baos = new ByteArrayOutputStream(100); + DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos)); + + try { + dos.writeInt(env.messageType); + dos.writeInt(env.teleService); + dos.writeInt(env.serviceCategory); + + dos.writeByte(addr.digitMode); + dos.writeByte(addr.numberMode); + dos.writeByte(addr.ton); + dos.writeByte(addr.numberPlan); + dos.writeByte(addr.numberOfDigits); + dos.write(addr.origBytes, 0, addr.origBytes.length); // digits + + dos.writeInt(env.bearerReply); + // CauseCode values: + dos.writeByte(env.replySeqNo); + dos.writeByte(env.errorClass); + dos.writeByte(env.causeCode); + //encoded BearerData: + dos.writeInt(env.bearerData.length); + dos.write(env.bearerData, 0, env.bearerData.length); + dos.close(); + + mPdu = baos.toByteArray(); + } catch (IOException ex) { + Log.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex); + } + } + + /** + * Converts a 4-Bit DTMF encoded symbol from the calling address number to ASCII character + */ + private byte convertDtmfToAscii(byte dtmfDigit) { + byte asciiDigit; + + switch (dtmfDigit) { + case 0: asciiDigit = 68; break; // 'D' + case 1: asciiDigit = 49; break; // '1' + case 2: asciiDigit = 50; break; // '2' + case 3: asciiDigit = 51; break; // '3' + case 4: asciiDigit = 52; break; // '4' + case 5: asciiDigit = 53; break; // '5' + case 6: asciiDigit = 54; break; // '6' + case 7: asciiDigit = 55; break; // '7' + case 8: asciiDigit = 56; break; // '8' + case 9: asciiDigit = 57; break; // '9' + case 10: asciiDigit = 48; break; // '0' + case 11: asciiDigit = 42; break; // '*' + case 12: asciiDigit = 35; break; // '#' + case 13: asciiDigit = 65; break; // 'A' + case 14: asciiDigit = 66; break; // 'B' + case 15: asciiDigit = 67; break; // 'C' + default: + asciiDigit = 32; // Invalid DTMF code + break; + } + + return asciiDigit; + } + + + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java new file mode 100644 index 0000000000000000000000000000000000000000..f27f79cd9ebe15a7f61346b38459f2c980f5206b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java @@ -0,0 +1,46 @@ +/* + * 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.cdma; + +public class TtyIntent { + + private static final String TAG = "TtyIntent"; + + + /** Event for TTY mode change */ + + /** + * Broadcast intent action indicating that the TTY has either been + * enabled or disabled. An intent extra provides this state as a boolean, + * where {@code true} means enabled. + * @see #TTY_ENABLED + * + * {@hide} + */ + public static final String TTY_ENABLED_CHANGE_ACTION = + "com.android.internal.telephony.cdma.intent.action.TTY_ENABLED_CHANGE"; + + /** + * The lookup key for a boolean that indicates whether TTY mode is enabled or + * disabled. {@code true} means TTY mode is enabled. Retrieve it with + * {@link android.content.Intent#getBooleanExtra(String,boolean)}. + * + * {@hide} + */ + public static final String TTY_ENABLED = "ttyEnabled"; + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/package.html b/telephony/java/com/android/internal/telephony/cdma/package.html new file mode 100644 index 0000000000000000000000000000000000000000..cf1ad4a046bff8d732263211c1a5a885b900bfaa --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/package.html @@ -0,0 +1,6 @@ + + +Provides classes to control or read data from CDMA phones. +@hide + + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java new file mode 100644 index 0000000000000000000000000000000000000000..e64d0224253b0d3cea4a9af806f7c5c14803b6eb --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -0,0 +1,989 @@ +/* + * 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.cdma.sms; + +import android.util.Log; + +import android.telephony.SmsMessage; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.cdma.sms.UserData; + +import com.android.internal.util.HexDump; +import com.android.internal.util.BitwiseInputStream; +import com.android.internal.util.BitwiseOutputStream; + + +/** + * An object to encode and decode CDMA SMS bearer data. + */ +public final class BearerData{ + private final static String LOG_TAG = "SMS"; + + /** + * Bearer Data Subparameter Indentifiers + * (See 3GPP2 C.S0015-B, v2.0, table 4.5-1) + */ + private final static byte SUBPARAM_MESSAGE_IDENTIFIER = 0x00; + private final static byte SUBPARAM_USER_DATA = 0x01; + private final static byte SUBPARAM_USER_REPONSE_CODE = 0x02; + private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP = 0x03; + //private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE = 0x04; + //private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05; + //private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE = 0x06; + //private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE = 0x07; + private final static byte SUBPARAM_PRIORITY_INDICATOR = 0x08; + private final static byte SUBPARAM_PRIVACY_INDICATOR = 0x09; + private final static byte SUBPARAM_REPLY_OPTION = 0x0A; + private final static byte SUBPARAM_NUMBER_OF_MESSAGES = 0x0B; + private final static byte SUBPARAM_ALERT_ON_MESSAGE_DELIVERY = 0x0C; + private final static byte SUBPARAM_LANGUAGE_INDICATOR = 0x0D; + private final static byte SUBPARAM_CALLBACK_NUMBER = 0x0E; + private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE = 0x0F; + //private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA = 0x10; + //private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX = 0x11; + //private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12; + //private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS = 0x13; + private final static byte SUBPARAM_MESSAGE_STATUS = 0x14; + //private final static byte SUBPARAM_TP_FAILURE_CAUSE = 0x15; + //private final static byte SUBPARAM_ENHANCED_VMN = 0x16; + //private final static byte SUBPARAM_ENHANCED_VMN_ACK = 0x17; + + /** + * Supported message types for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1) + */ + public static final int MESSAGE_TYPE_DELIVER = 0x01; + public static final int MESSAGE_TYPE_SUBMIT = 0x02; + public static final int MESSAGE_TYPE_CANCELLATION = 0x03; + public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04; + public static final int MESSAGE_TYPE_USER_ACK = 0x05; + public static final int MESSAGE_TYPE_READ_ACK = 0x06; + public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07; + public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08; + + public byte messageType; + + /** + * 16-bit value indicating the message ID, which increments modulo 65536. + * (Special rules apply for WAP-messages.) + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public int messageId; + + /** + * Supported priority modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1) + */ + public static final int PRIORITY_NORMAL = 0x0; + public static final int PRIORITY_INTERACTIVE = 0x1; + public static final int PRIORITY_URGENT = 0x2; + public static final int PRIORITY_EMERGENCY = 0x3; + + public boolean priorityIndicatorSet = false; + public byte priority = PRIORITY_NORMAL; + + /** + * Supported privacy modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1) + */ + public static final int PRIVACY_NOT_RESTRICTED = 0x0; + public static final int PRIVACY_RESTRICTED = 0x1; + public static final int PRIVACY_CONFIDENTIAL = 0x2; + public static final int PRIVACY_SECRET = 0x3; + + public boolean privacyIndicatorSet = false; + public byte privacy = PRIVACY_NOT_RESTRICTED; + + /** + * Supported alert priority modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1) + */ + public static final int ALERT_DEFAULT = 0x0; + public static final int ALERT_LOW_PRIO = 0x1; + public static final int ALERT_MEDIUM_PRIO = 0x2; + public static final int ALERT_HIGH_PRIO = 0x3; + + public boolean alertIndicatorSet = false; + public int alert = ALERT_DEFAULT; + + /** + * Supported display modes for CDMA SMS messages. Display mode is + * a 2-bit value used to indicate to the mobile station when to + * display the received message. (See 3GPP2 C.S0015-B, v2, + * 4.5.16) + */ + public static final int DISPLAY_MODE_IMMEDIATE = 0x0; + public static final int DISPLAY_MODE_DEFAULT = 0x1; + public static final int DISPLAY_MODE_USER = 0x2; + + public boolean displayModeSet = false; + public byte displayMode = DISPLAY_MODE_DEFAULT; + + /** + * Language Indicator values. NOTE: the spec (3GPP2 C.S0015-B, + * v2, 4.5.14) is ambiguous as to the meaning of this field, as it + * refers to C.R1001-D but that reference has been crossed out. + * It would seem reasonable to assume the values from C.R1001-F + * (table 9.2-1) are to be used instead. + */ + public static final int LANGUAGE_UNKNOWN = 0x00; + public static final int LANGUAGE_ENGLISH = 0x01; + public static final int LANGUAGE_FRENCH = 0x02; + public static final int LANGUAGE_SPANISH = 0x03; + public static final int LANGUAGE_JAPANESE = 0x04; + public static final int LANGUAGE_KOREAN = 0x05; + public static final int LANGUAGE_CHINESE = 0x06; + public static final int LANGUAGE_HEBREW = 0x07; + + public boolean languageIndicatorSet = false; + public int language = LANGUAGE_UNKNOWN; + + /** + * SMS Message Status Codes. The first component of the Message + * status indicates if an error has occurred and whether the error + * is considered permanent or temporary. The second component of + * the Message status indicates the cause of the error (if any). + * (See 3GPP2 C.S0015-B, v2.0, 4.5.21) + */ + /* no-error codes */ + public static final int ERROR_NONE = 0x00; + public static final int STATUS_ACCEPTED = 0x00; + public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01; + public static final int STATUS_DELIVERED = 0x02; + public static final int STATUS_CANCELLED = 0x03; + /* temporary-error and permanent-error codes */ + public static final int ERROR_TEMPORARY = 0x02; + public static final int STATUS_NETWORK_CONGESTION = 0x04; + public static final int STATUS_NETWORK_ERROR = 0x05; + public static final int STATUS_UNKNOWN_ERROR = 0x1F; + /* permanent-error codes */ + public static final int ERROR_PERMANENT = 0x03; + public static final int STATUS_CANCEL_FAILED = 0x06; + public static final int STATUS_BLOCKED_DESTINATION = 0x07; + public static final int STATUS_TEXT_TOO_LONG = 0x08; + public static final int STATUS_DUPLICATE_MESSAGE = 0x09; + public static final int STATUS_INVALID_DESTINATION = 0x0A; + public static final int STATUS_MESSAGE_EXPIRED = 0x0D; + /* undefined-status codes */ + public static final int ERROR_UNDEFINED = 0xFF; + public static final int STATUS_UNDEFINED = 0xFF; + + public boolean messageStatusSet = false; + public int errorClass = ERROR_UNDEFINED; + public int messageStatus = STATUS_UNDEFINED; + + /** + * 1-bit value that indicates whether a User Data Header is present. + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public boolean hasUserDataHeader; + + /** + * provides the information for the user data + * (e.g. padding bits, user data, user data header, etc) + * (See 3GPP2 C.S.0015-B, v2, 4.5.2) + */ + public UserData userData; + + //public UserResponseCode userResponseCode; + + /** + * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4 + * year, month, day, hours, minutes, seconds; + */ + public byte[] timeStamp; + + //public SmsTime validityPeriodAbsolute; + //public SmsRelTime validityPeriodRelative; + //public SmsTime deferredDeliveryTimeAbsolute; + //public SmsRelTime deferredDeliveryTimeRelative; + + /** + * Reply Option + * 1-bit values which indicate whether SMS acknowledgment is requested or not. + * (See 3GPP2 C.S0015-B, v2, 4.5.11) + */ + public boolean userAckReq; + public boolean deliveryAckReq; + public boolean readAckReq; + public boolean reportReq; + + /** + * The number of Messages element (8-bit value) is a decimal number in the 0 to 99 range + * representing the number of messages stored at the Voice Mail System. This element is + * used by the Voice Mail Notification service. + * (See 3GPP2 C.S0015-B, v2, 4.5.12) + */ + public int numberOfMessages; + + /** + * 4-bit or 8-bit value that indicates the number to be dialed in reply to a + * received SMS message. + * (See 3GPP2 C.S0015-B, v2, 4.5.15) + */ + public CdmaSmsAddress callbackNumber; + + private static class CodingException extends Exception { + public CodingException(String s) { + super(s); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("BearerData:\n"); + builder.append(" messageType: " + messageType + "\n"); + builder.append(" messageId: " + (int)messageId + "\n"); + builder.append(" priority: " + (priorityIndicatorSet ? priority : "not set") + "\n"); + builder.append(" privacy: " + (privacyIndicatorSet ? privacy : "not set") + "\n"); + builder.append(" alert: " + (alertIndicatorSet ? alert : "not set") + "\n"); + builder.append(" displayMode: " + (displayModeSet ? displayMode : "not set") + "\n"); + builder.append(" language: " + (languageIndicatorSet ? language : "not set") + "\n"); + builder.append(" errorClass: " + (messageStatusSet ? errorClass : "not set") + "\n"); + builder.append(" msgStatus: " + (messageStatusSet ? messageStatus : "not set") + "\n"); + builder.append(" hasUserDataHeader: " + hasUserDataHeader + "\n"); + builder.append(" timeStamp: " + timeStamp + "\n"); + builder.append(" userAckReq: " + userAckReq + "\n"); + builder.append(" deliveryAckReq: " + deliveryAckReq + "\n"); + builder.append(" readAckReq: " + readAckReq + "\n"); + builder.append(" reportReq: " + reportReq + "\n"); + builder.append(" numberOfMessages: " + numberOfMessages + "\n"); + builder.append(" callbackNumber: " + callbackNumber + "\n"); + builder.append(" userData: " + userData + "\n"); + return builder.toString(); + } + + private static void encodeMessageId(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 3); + outStream.write(4, bData.messageType); + outStream.write(8, bData.messageId >> 8); + outStream.write(8, bData.messageId); + outStream.write(1, bData.hasUserDataHeader ? 1 : 0); + outStream.skip(3); + } + + private static byte[] encode7bitAscii(String msg) + throws CodingException + { + try { + BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length()); + byte[] expandedData = msg.getBytes("US-ASCII"); + for (int i = 0; i < expandedData.length; i++) { + int charCode = expandedData[i]; + // Test ourselves for ASCII membership, since Java seems not to care. + if ((charCode < UserData.PRINTABLE_ASCII_MIN_INDEX) || + (charCode > UserData.PRINTABLE_ASCII_MAX_INDEX)) { + throw new CodingException("illegal ASCII code (" + charCode + ")"); + } + outStream.write(7, expandedData[i]); + } + return outStream.toByteArray(); + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("7bit ASCII encode failed: " + ex); + } catch (BitwiseOutputStream.AccessException ex) { + throw new CodingException("7bit ASCII encode failed: " + ex); + } + } + + private static byte[] encodeUtf16(String msg) + throws CodingException + { + try { + return msg.getBytes("utf-16be"); // XXX(do not submit) -- make sure decode matches + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("UTF-16 encode failed: " + ex); + } + } + + private static byte[] encode7bitGsm(String msg) + throws CodingException + { + try { + /** + * TODO(cleanup): find some way to do this without the copy. + */ + byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg); + byte []data = new byte[fullData.length - 1]; + for (int i = 0; i < data.length; i++) { + data[i] = fullData[i + 1]; + } + return data; + } catch (com.android.internal.telephony.EncodeException ex) { + throw new CodingException("7bit GSM encode failed: " + ex); + } + } + + private static void encodeUserDataPayload(UserData uData) + throws CodingException + { + if (uData.msgEncodingSet) { + if (uData.msgEncoding == UserData.ENCODING_OCTET) { + if (uData.payload == null) { + Log.e(LOG_TAG, "user data with octet encoding but null payload"); + // TODO(code_review): reasonable for fail case? or maybe bail on encoding? + uData.payload = new byte[0]; + } + } else { + if (uData.payloadStr == null) { + Log.e(LOG_TAG, "non-octet user data with null payloadStr"); + // TODO(code_review): reasonable for fail case? or maybe bail on encoding? + uData.payloadStr = ""; + } + if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) { + uData.payload = encode7bitGsm(uData.payloadStr); + } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) { + uData.payload = encode7bitAscii(uData.payloadStr); + } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) { + uData.payload = encodeUtf16(uData.payloadStr); + } else { + throw new CodingException("unsupported user data encoding (" + + uData.msgEncoding + ")"); + } + uData.numFields = uData.payloadStr.length(); + } + } else { + if (uData.payloadStr == null) { + Log.e(LOG_TAG, "user data with null payloadStr"); + // TODO(code_review): reasonable for fail case? or maybe bail on encoding? + uData.payloadStr = ""; + } + try { + uData.payload = encode7bitAscii(uData.payloadStr); + uData.msgEncoding = UserData.ENCODING_7BIT_ASCII; + } catch (CodingException ex) { + uData.payload = encodeUtf16(uData.payloadStr); + uData.msgEncoding = UserData.ENCODING_UNICODE_16; + } + uData.msgEncodingSet = true; + uData.numFields = uData.payloadStr.length(); + } + if (uData.payload.length > SmsMessage.MAX_USER_DATA_BYTES) { + throw new CodingException("encoded user data too large (" + uData.payload.length + + " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)"); + } + } + + private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException, CodingException + { + encodeUserDataPayload(bData.userData); + /** + * XXX/TODO: figure out what the right answer is WRT padding bits + * + * userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7); + * userData.paddingBits = 0; // XXX this seems better, but why? + * + */ + int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits; + byte[] headerData = null; + if (bData.hasUserDataHeader) { + headerData = bData.userData.userDataHeader.toByteArray(); + dataBits += headerData.length * 8; + } + int paramBits = dataBits + 13; + if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) || + (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) { + paramBits += 8; + } + int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0); + int paddingBits = (paramBytes * 8) - paramBits; + outStream.write(8, paramBytes); + outStream.write(5, bData.userData.msgEncoding); + if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) || + (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) { + outStream.write(8, bData.userData.msgType); + } + outStream.write(8, bData.userData.numFields); + if (headerData != null) outStream.writeByteArray(headerData.length * 8, headerData); + outStream.writeByteArray(dataBits, bData.userData.payload); + if (paddingBits > 0) outStream.write(paddingBits, 0); + } + + private static void encodeReplyOption(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(1, bData.userAckReq ? 1 : 0); + outStream.write(1, bData.deliveryAckReq ? 1 : 0); + outStream.write(1, bData.readAckReq ? 1 : 0); + outStream.write(1, bData.reportReq ? 1 : 0); + outStream.write(4, 0); + } + + private static byte[] encodeDtmfSmsAddress(String address) { + int digits = address.length(); + int dataBits = digits * 4; + int dataBytes = (dataBits / 8); + dataBytes += (dataBits % 8) > 0 ? 1 : 0; + byte[] rawData = new byte[dataBytes]; + for (int i = 0; i < digits; i++) { + char c = address.charAt(i); + int val = 0; + if ((c >= '1') && (c <= '9')) val = c - '0'; + else if (c == '0') val = 10; + else if (c == '*') val = 11; + else if (c == '#') val = 12; + else return null; + rawData[i / 2] |= val << (4 - ((i % 2) * 4)); + } + return rawData; + } + + private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException { + if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { + try { + addr.origBytes = addr.address.getBytes("US-ASCII"); + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("invalid SMS address, cannot convert to ASCII"); + } + } else { + addr.origBytes = encodeDtmfSmsAddress(addr.address); + } + } + + private static void encodeCallbackNumber(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException, CodingException + { + CdmaSmsAddress addr = bData.callbackNumber; + encodeCdmaSmsAddress(addr); + int paramBits = 9; + int dataBits = 0; + if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { + paramBits += 7; + dataBits = addr.numberOfDigits * 8; + } else { + dataBits = addr.numberOfDigits * 4; + } + paramBits += dataBits; + int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0); + int paddingBits = (paramBytes * 8) - paramBits; + outStream.write(8, paramBytes); + outStream.write(1, addr.digitMode); + if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { + outStream.write(3, addr.ton); + outStream.write(4, addr.numberPlan); + } + outStream.write(8, addr.numberOfDigits); + outStream.writeByteArray(dataBits, addr.origBytes); + if (paddingBits > 0) outStream.write(paddingBits, 0); + } + + private static void encodeMsgStatus(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(2, bData.errorClass); + outStream.write(6, bData.messageStatus); + } + + private static void encodeMsgCount(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(8, bData.numberOfMessages); + } + + private static void encodeMsgCenterTimeStamp(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 6); + outStream.writeByteArray(6 * 8, bData.timeStamp); + } + + private static void encodePrivacyIndicator(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(2, bData.privacy); + outStream.skip(6); + } + + private static void encodeLanguageIndicator(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(8, bData.language); + } + + private static void encodeDisplayMode(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(2, bData.displayMode); + outStream.skip(6); + } + + private static void encodePriorityIndicator(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(2, bData.priority); + outStream.skip(6); + } + + private static void encodeMsgDeliveryAlert(BearerData bData, BitwiseOutputStream outStream) + throws BitwiseOutputStream.AccessException + { + outStream.write(8, 1); + outStream.write(2, bData.alert); + outStream.skip(6); + } + + /** + * Create serialized representation for BearerData object. + * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details) + * + * @param bearerData an instance of BearerData. + * + * @return data byta array of raw encoded SMS bearer data. + */ + public static byte[] encode(BearerData bData) { + try { + BitwiseOutputStream outStream = new BitwiseOutputStream(200); + outStream.write(8, SUBPARAM_MESSAGE_IDENTIFIER); + encodeMessageId(bData, outStream); + if (bData.userData != null) { + outStream.write(8, SUBPARAM_USER_DATA); + encodeUserData(bData, outStream); + } + if (bData.callbackNumber != null) { + outStream.write(8, SUBPARAM_CALLBACK_NUMBER); + encodeCallbackNumber(bData, outStream); + } + if (bData.userAckReq || bData.deliveryAckReq || bData.readAckReq || bData.reportReq) { + outStream.write(8, SUBPARAM_REPLY_OPTION); + encodeReplyOption(bData, outStream); + } + if (bData.numberOfMessages != 0) { + outStream.write(8, SUBPARAM_NUMBER_OF_MESSAGES); + encodeMsgCount(bData, outStream); + } + if (bData.timeStamp != null) { + outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP); + encodeMsgCenterTimeStamp(bData, outStream); + } + if (bData.privacyIndicatorSet) { + outStream.write(8, SUBPARAM_PRIVACY_INDICATOR); + encodePrivacyIndicator(bData, outStream); + } + if (bData.languageIndicatorSet) { + outStream.write(8, SUBPARAM_LANGUAGE_INDICATOR); + encodeLanguageIndicator(bData, outStream); + } + if (bData.displayModeSet) { + outStream.write(8, SUBPARAM_MESSAGE_DISPLAY_MODE); + encodeDisplayMode(bData, outStream); + } + if (bData.priorityIndicatorSet) { + outStream.write(8, SUBPARAM_PRIORITY_INDICATOR); + encodePriorityIndicator(bData, outStream); + } + if (bData.alertIndicatorSet) { + outStream.write(8, SUBPARAM_ALERT_ON_MESSAGE_DELIVERY); + encodeMsgDeliveryAlert(bData, outStream); + } + if (bData.messageStatusSet) { + outStream.write(8, SUBPARAM_MESSAGE_STATUS); + encodeMsgStatus(bData, outStream); + } + return outStream.toByteArray(); + } catch (BitwiseOutputStream.AccessException ex) { + Log.e(LOG_TAG, "BearerData encode failed: " + ex); + } catch (CodingException ex) { + Log.e(LOG_TAG, "BearerData encode failed: " + ex); + } + return null; + } + + private static void decodeMessageId(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 3) { + throw new CodingException("MESSAGE_IDENTIFIER subparam size incorrect"); + } + bData.messageType = inStream.read(4); + bData.messageId = inStream.read(8) << 8; + bData.messageId |= inStream.read(8); + bData.hasUserDataHeader = (inStream.read(1) == 1); + inStream.skip(3); + } + + private static void decodeUserData(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException + { + byte paramBytes = inStream.read(8); + bData.userData = new UserData(); + bData.userData.msgEncoding = inStream.read(5); + bData.userData.msgEncodingSet = true; + bData.userData.msgType = 0; + int consumedBits = 5; + if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) || + (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) { + bData.userData.msgType = inStream.read(8); + consumedBits += 8; + } + bData.userData.numFields = inStream.read(8); + consumedBits += 8; + int dataBits = (paramBytes * 8) - consumedBits; + bData.userData.payload = inStream.readByteArray(dataBits); + } + + private static String decodeUtf16(byte[] data, int offset, int numFields) + throws CodingException + { + try { + return new String(data, offset, numFields * 2, "utf-16be"); + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("UTF-16 decode failed: " + ex); + } + } + + private static String decodeIa5(byte[] data, int offset, int numFields) + throws CodingException + { + try { + offset *= 8; + StringBuffer strBuf = new StringBuffer(numFields); + BitwiseInputStream inStream = new BitwiseInputStream(data); + int wantedBits = (offset * 8) + (numFields * 7); + if (inStream.available() < wantedBits) { + throw new CodingException("insufficient data (wanted " + wantedBits + + " bits, but only have " + inStream.available() + ")"); + } + inStream.skip(offset); + for (int i = 0; i < numFields; i++) { + int charCode = inStream.read(7); + if ((charCode < UserData.IA5_MAP_BASE_INDEX) || + (charCode > UserData.IA5_MAP_MAX_INDEX)) { + throw new CodingException("unsupported AI5 character code (" + charCode + ")"); + } + strBuf.append(UserData.IA5_MAP[charCode - UserData.IA5_MAP_BASE_INDEX]); + } + return strBuf.toString(); + } catch (BitwiseInputStream.AccessException ex) { + throw new CodingException("AI5 decode failed: " + ex); + } + } + + private static String decode7bitAscii(byte[] data, int offset, int numFields) + throws CodingException + { + try { + offset *= 8; + BitwiseInputStream inStream = new BitwiseInputStream(data); + int wantedBits = offset + (numFields * 7); + if (inStream.available() < wantedBits) { + throw new CodingException("insufficient data (wanted " + wantedBits + + " bits, but only have " + inStream.available() + ")"); + } + inStream.skip(offset); + byte[] expandedData = new byte[numFields]; + for (int i = 0; i < numFields; i++) { + expandedData[i] = inStream.read(7); + } + return new String(expandedData, 0, numFields, "US-ASCII"); + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("7bit ASCII decode failed: " + ex); + } catch (BitwiseInputStream.AccessException ex) { + throw new CodingException("7bit ASCII decode failed: " + ex); + } + } + + private static String decode7bitGsm(byte[] data, int offset, int numFields) + throws CodingException + { + String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields); + if (result == null) { + throw new CodingException("7bit GSM decoding failed"); + } + return result; + } + + private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader) + throws CodingException + { + int offset = 0; + if (hasUserDataHeader) { + int udhLen = userData.payload[0]; + offset += udhLen; + byte[] headerData = new byte[udhLen]; + System.arraycopy(userData.payload, 1, headerData, 0, udhLen); + userData.userDataHeader = SmsHeader.parse(headerData); + } + switch (userData.msgEncoding) { + case UserData.ENCODING_OCTET: + break; + case UserData.ENCODING_7BIT_ASCII: + userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields); + break; + case UserData.ENCODING_IA5: + userData.payloadStr = decodeIa5(userData.payload, offset, userData.numFields); + break; + case UserData.ENCODING_UNICODE_16: + userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields); + break; + case UserData.ENCODING_GSM_7BIT_ALPHABET: + userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields); + break; + default: + throw new CodingException("unsupported user data encoding (" + + userData.msgEncoding + ")"); + } + } + + private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + byte paramBytes = inStream.read(8); + if (paramBytes != 1) { + throw new CodingException("REPLY_OPTION subparam size incorrect"); + } + bData.userAckReq = (inStream.read(1) == 1); + bData.deliveryAckReq = (inStream.read(1) == 1); + bData.readAckReq = (inStream.read(1) == 1); + bData.reportReq = (inStream.read(1) == 1); + inStream.skip(4); + } + + private static void decodeMsgCount(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("NUMBER_OF_MESSAGES subparam size incorrect"); + } + bData.numberOfMessages = inStream.read(8); + } + + private static String decodeDtmfSmsAddress(byte[] rawData, int numFields) + throws CodingException + { + /* DTMF 4-bit digit encoding, defined in at + * 3GPP2 C.S005-D, v2.0, table 2.7.1.3.2.4-4 */ + StringBuffer strBuf = new StringBuffer(numFields); + for (int i = 0; i < numFields; i++) { + int val = 0x0F & (rawData[i / 2] >>> (4 - ((i % 2) * 4))); + if ((val >= 1) && (val <= 9)) strBuf.append(Integer.toString(val, 10)); + else if (val == 10) strBuf.append('0'); + else if (val == 11) strBuf.append('*'); + else if (val == 12) strBuf.append('#'); + else throw new CodingException("invalid SMS address DTMF code (" + val + ")"); + } + return strBuf.toString(); + } + + private static void decodeSmsAddress(CdmaSmsAddress addr) throws CodingException { + if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { + try { + /* As specified in 3GPP2 C.S0015-B, v2, 4.5.15 -- actually + * just 7-bit ASCII encoding, with the MSB being zero. */ + addr.address = new String(addr.origBytes, 0, addr.origBytes.length, "US-ASCII"); + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("invalid SMS address ASCII code"); + } + } else { + addr.address = decodeDtmfSmsAddress(addr.origBytes, addr.numberOfDigits); + } + } + + private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + byte paramBytes = inStream.read(8); + CdmaSmsAddress addr = new CdmaSmsAddress(); + addr.digitMode = inStream.read(1); + byte fieldBits = 4; + byte consumedBits = 1; + if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { + addr.ton = inStream.read(3); + addr.numberPlan = inStream.read(4); + fieldBits = 8; + consumedBits += 7; + } + addr.numberOfDigits = inStream.read(8); + consumedBits += 8; + int remainingBits = (paramBytes * 8) - consumedBits; + int dataBits = addr.numberOfDigits * fieldBits; + int paddingBits = remainingBits - dataBits; + if (remainingBits < dataBits) { + throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" + + "remainingBits " + remainingBits + ", dataBits " + + dataBits + ", paddingBits " + paddingBits + ")"); + } + addr.origBytes = inStream.readByteArray(dataBits); + inStream.skip(paddingBits); + decodeSmsAddress(addr); + bData.callbackNumber = addr; + } + + private static void decodeMsgStatus(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("MESSAGE_STATUS subparam size incorrect"); + } + bData.errorClass = inStream.read(2); + bData.messageStatus = inStream.read(6); + bData.messageStatusSet = true; + } + + private static void decodeMsgCenterTimeStamp(BearerData bData, + BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 6) { + throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect"); + } + bData.timeStamp = inStream.readByteArray(6 * 8); + } + + private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("PRIVACY_INDICATOR subparam size incorrect"); + } + bData.privacy = inStream.read(2); + inStream.skip(6); + bData.privacyIndicatorSet = true; + } + + private static void decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("LANGUAGE_INDICATOR subparam size incorrect"); + } + bData.language = inStream.read(8); + bData.languageIndicatorSet = true; + } + + private static void decodeDisplayMode(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("DISPLAY_MODE subparam size incorrect"); + } + bData.displayMode = inStream.read(2); + inStream.skip(6); + bData.displayModeSet = true; + } + + private static void decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("PRIORITY_INDICATOR subparam size incorrect"); + } + bData.priority = inStream.read(2); + inStream.skip(6); + bData.priorityIndicatorSet = true; + } + + private static void decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream) + throws BitwiseInputStream.AccessException, CodingException + { + if (inStream.read(8) != 1) { + throw new CodingException("ALERT_ON_MESSAGE_DELIVERY subparam size incorrect"); + } + bData.alert = inStream.read(2); + inStream.skip(6); + bData.alertIndicatorSet = true; + } + + /** + * Create BearerData object from serialized representation. + * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details) + * + * @param smsData byte array of raw encoded SMS bearer data. + * + * @return an instance of BearerData. + */ + public static BearerData decode(byte[] smsData) { + try { + BitwiseInputStream inStream = new BitwiseInputStream(smsData); + BearerData bData = new BearerData(); + int foundSubparamMask = 0; + while (inStream.available() > 0) { + int subparamId = inStream.read(8); + int subparamIdBit = 1 << subparamId; + if ((foundSubparamMask & subparamIdBit) != 0) { + throw new CodingException("illegal duplicate subparameter (" + + subparamId + ")"); + } + foundSubparamMask |= subparamIdBit; + switch (subparamId) { + case SUBPARAM_MESSAGE_IDENTIFIER: + decodeMessageId(bData, inStream); + break; + case SUBPARAM_USER_DATA: + decodeUserData(bData, inStream); + break; + case SUBPARAM_REPLY_OPTION: + decodeReplyOption(bData, inStream); + break; + case SUBPARAM_NUMBER_OF_MESSAGES: + decodeMsgCount(bData, inStream); + break; + case SUBPARAM_CALLBACK_NUMBER: + decodeCallbackNumber(bData, inStream); + break; + case SUBPARAM_MESSAGE_STATUS: + decodeMsgStatus(bData, inStream); + break; + case SUBPARAM_MESSAGE_CENTER_TIME_STAMP: + decodeMsgCenterTimeStamp(bData, inStream); + break; + case SUBPARAM_PRIVACY_INDICATOR: + decodePrivacyIndicator(bData, inStream); + break; + case SUBPARAM_LANGUAGE_INDICATOR: + decodeLanguageIndicator(bData, inStream); + break; + case SUBPARAM_MESSAGE_DISPLAY_MODE: + decodeDisplayMode(bData, inStream); + break; + case SUBPARAM_PRIORITY_INDICATOR: + decodePriorityIndicator(bData, inStream); + break; + case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY: + decodeMsgDeliveryAlert(bData, inStream); + break; + default: + throw new CodingException("unsupported bearer data subparameter (" + + subparamId + ")"); + } + } + if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) { + throw new CodingException("missing MESSAGE_IDENTIFIER subparam"); + } + if (bData.userData != null) { + decodeUserDataPayload(bData.userData, bData.hasUserDataHeader); + } + return bData; + } catch (BitwiseInputStream.AccessException ex) { + Log.e(LOG_TAG, "BearerData decode failed: " + ex); + } catch (CodingException ex) { + Log.e(LOG_TAG, "BearerData decode failed: " + ex); + } + return null; + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java new file mode 100644 index 0000000000000000000000000000000000000000..440debbd354ee18118daff09656cf4433e77de3a --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java @@ -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. + */ + +package com.android.internal.telephony.cdma.sms; + +import com.android.internal.telephony.SmsAddress; +import com.android.internal.util.HexDump; + +public class CdmaSmsAddress extends SmsAddress { + /** + * digit mode indicators + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + static public final int DIGIT_MODE_4BIT_DTMF = 0x00; + static public final int DIGIT_MODE_8BIT_CHAR = 0x01; + + /** + * number mode indicators + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00; + static public final int NUMBER_MODE_DATA_NETWORK = 0x01; + + /** + * number types for data networks + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + static public final int TON_UNKNOWN = 0x00; + static public final int TON_INTERNATIONAL_OR_IP = 0x01; + static public final int TON_NATIONAL_OR_EMAIL = 0x02; + static public final int TON_NETWORK = 0x03; + static public final int TON_SUBSCRIBER = 0x04; + static public final int TON_ALPHANUMERIC = 0x05; + static public final int TON_ABBREVIATED = 0x06; + static public final int TON_RESERVED = 0x07; + + /** + * maximum lengths for fields as defined in ril_cdma_sms.h + */ + static public final int SMS_ADDRESS_MAX = 36; + static public final int SMS_SUBADDRESS_MAX = 36; + + /** + * Supported numbering plan identification + * (See C.S005-D, v1.0, table 2.7.1.3.2.4-3) + */ + static public final int NUMBERING_PLAN_UNKNOWN = 0x0; + static public final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1; + //static protected final int NUMBERING_PLAN_DATA = 0x3; + //static protected final int NUMBERING_PLAN_TELEX = 0x4; + //static protected final int NUMBERING_PLAN_PRIVATE = 0x9; + + /** + * 1-bit value that indicates whether the address digits are 4-bit DTMF codes + * or 8-bit codes. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + public byte digitMode; + + /** + * 1-bit value that indicates whether the address type is a data network address or not. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + public byte numberMode; + + // use parent class member ton instead public byte numberType; + + /** + * 0 or 4-bit value that indicates which numbering plan identification is set. + * (See 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3) + */ + public byte numberPlan; + + /** + * This field shall be set to the number of address digits + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + public byte numberOfDigits; + + // use parent class member orig_bytes instead of public byte[] digits; + + // Constructor + public CdmaSmsAddress(){ + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("CdmaSmsAddress:\n"); + builder.append(" digitMode: " + digitMode + "\n"); + builder.append(" numberMode: " + numberMode + "\n"); + builder.append(" numberPlan: " + numberPlan + "\n"); + builder.append(" numberOfDigits: " + numberOfDigits + "\n"); + builder.append(" ton: " + ton + "\n"); + builder.append(" address: " + address + "\n"); + builder.append(" origBytes: " + HexDump.toHexString(origBytes) + "\n"); + return builder.toString(); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java new file mode 100644 index 0000000000000000000000000000000000000000..f80e8c091b7d154a87471d3d55c260b17b459d05 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.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 com.android.internal.telephony.cdma.sms; + + +public final class SmsEnvelope{ + /** + * Message Types + * (See 3GPP2 C.S0015-B 3.4.1) + */ + static public final int MESSAGE_TYPE_POINT_TO_POINT = 0x00; + static public final int MESSAGE_TYPE_BROADCAST = 0x01; + static public final int MESSAGE_TYPE_ACKNOWLEDGE = 0x02; + + /** + * Supported Teleservices + * (See 3GPP2 N.S0005 and TIA-41) + */ + static public final int TELESERVICE_NOT_SET = 0x0000; + static public final int TELESERVICE_WMT = 0x1002; + static public final int TELESERVICE_VMN = 0x1003; + static public final int TELESERVICE_WAP = 0x1004; + static public final int TELESERVICE_WEMT = 0x1005; + + // ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1 + //static public final int SERVICECATEGORY_EMERGENCY = 0x0010; + //... + + /** + * maximum lengths for fields as defined in ril_cdma_sms.h + */ + static public final int SMS_BEARER_DATA_MAX = 255; + + /** + * Provides the type of a SMS message like point to point, broadcast or acknowledge + */ + public int messageType; + + /** + * The 16-bit Teleservice parameter identifies which upper layer service access point is sending + * or receiving the message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.1) + */ + public int teleService = TELESERVICE_NOT_SET; + + /** + * The 16-bit service category parameter identifies the type of service provided + * by the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.2) + */ + public int serviceCategory; + + /** + * The origination address identifies the originator of the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.4) + */ + public CdmaSmsAddress origAddress; + + /** + * The destination address identifies the target of the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.4) + */ + public CdmaSmsAddress destAddress; + + /** + * The 6-bit bearer reply parameter is used to request the return of a + * SMS Acknowledge Message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.5) + */ + public int bearerReply; + + /** + * Cause Code values: + * The cause code parameters are an indication whether an SMS error has occurred and if so, + * whether the condition is considered temporary or permanent. + * ReplySeqNo 6-bit value, + * ErrorClass 2-bit value, + * CauseCode 0-bit or 8-bit value + * (See 3GPP2 C.S0015-B, v2, 3.4.3.6) + */ + public byte replySeqNo; + public byte errorClass; + public byte causeCode; + + /** + * encoded bearer data + * (See 3GPP2 C.S0015-B, v2, 3.4.3.7) + */ + public byte[] bearerData; + + public SmsEnvelope() { + // nothing to see here + } + +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java new file mode 100644 index 0000000000000000000000000000000000000000..02e94ad768f0cdbc1502193186ddfb5fe3ad2bd6 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.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 com.android.internal.telephony.cdma.sms; + +import com.android.internal.telephony.SmsHeader; +import com.android.internal.util.HexDump; + +public class UserData { + + /** + * User data encoding types. + * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1) + */ + public static final int ENCODING_OCTET = 0x00; + public static final int ENCODING_IS91_EXTENDED_PROTOCOL = 0x01; + public static final int ENCODING_7BIT_ASCII = 0x02; + public static final int ENCODING_IA5 = 0x03; + public static final int ENCODING_UNICODE_16 = 0x04; + //public static final int ENCODING_SHIFT_JIS = 0x05; + //public static final int ENCODING_KOREAN = 0x06; + //public static final int ENCODING_LATIN_HEBREW = 0x07; + //public static final int ENCODING_LATIN = 0x08; + public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09; + public static final int ENCODING_GSM_DCS = 0x0A; + + /** + * IA5 data encoding character mappings. + * (See CCITT Rec. T.50 Tables 1 and 3) + */ + public static final char[] IA5_MAP = { + ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'}; + + /** + * Only elements between these indices in the ASCII table are printable. + */ + public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20; + public static final int PRINTABLE_ASCII_MAX_INDEX = 0x7F; + + /** + * Mapping for IA5 values less than 32 are flow control signals + * and not used here. + */ + public static final int IA5_MAP_BASE_INDEX = 0x20; + public static final int IA5_MAP_MAX_INDEX = IA5_MAP_BASE_INDEX + IA5_MAP.length - 1; + + /** + * Contains the data header of the user data + */ + public SmsHeader userDataHeader; + + /** + * Contains the data encoding type for the SMS message + */ + public int msgEncoding; + public boolean msgEncodingSet = false; + + // XXX needed when encoding is IS91 or DCS (not supported yet): + public int msgType; + + /** + * Number of invalid bits in the last byte of data. + */ + public int paddingBits; + + public int numFields; + + /** + * Contains the user data of a SMS message + * (See 3GPP2 C.S0015-B, v2, 4.5.2) + */ + public byte[] payload; + public String payloadStr; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("UserData:\n"); + builder.append(" msgEncoding: " + (msgEncodingSet ? msgEncoding : "not set") + "\n"); + builder.append(" msgType: " + msgType + "\n"); + builder.append(" paddingBits: " + paddingBits + "\n"); + builder.append(" numFields: " + (int)numFields + "\n"); + builder.append(" userDataHeader: " + userDataHeader + "\n"); + builder.append(" payload: '" + HexDump.toHexString(payload) + "'"); + builder.append(", payloadStr: '" + payloadStr + "'"); + return builder.toString(); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/package.html b/telephony/java/com/android/internal/telephony/cdma/sms/package.html new file mode 100644 index 0000000000000000000000000000000000000000..48e10340cb86a879d5a4676ac04ceb39999069db --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/package.html @@ -0,0 +1,6 @@ + + +Provides CDMA-specific features for text/data/PDU SMS messages +@hide + + diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java b/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java deleted file mode 100644 index 30df6994d6d9787a87dcd2617192104748d372f5..0000000000000000000000000000000000000000 --- a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java +++ /dev/null @@ -1,570 +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; - -import com.android.internal.telephony.*; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.Message; -import android.os.Handler; -import android.os.Looper; -import android.os.AsyncResult; -import android.util.Log; -import android.telephony.PhoneNumberUtils; -import java.util.ArrayList; - -class AdnRecordLoader extends Handler -{ - static final String LOG_TAG = "GSM"; - - //***** Instance Variables - - GSMPhone phone; - int ef; - int extensionEF; - int pendingExtLoads; - Message userResponse; - String pin2; - - // For "load one" - int recordNumber; - - // for "load all" - ArrayList adns; // only valid after EVENT_ADN_LOAD_ALL_DONE - - // Either an AdnRecord or a reference to adns depending - // if this is a load one or load all operation - Object result; - - //***** Event Constants - - static final int EVENT_ADN_LOAD_DONE = 1; - static final int EVENT_EXT_RECORD_LOAD_DONE = 2; - static final int EVENT_ADN_LOAD_ALL_DONE = 3; - static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4; - static final int EVENT_UPDATE_RECORD_DONE = 5; - - //***** Constructor - - AdnRecordLoader(GSMPhone phone) - { - // The telephony unit-test cases may create AdnRecords - // in secondary threads - super(phone.h.getLooper()); - - this.phone = phone; - } - - /** - * Resulting AdnRecord is placed in response.obj.result - * or response.obj.exception is set - */ - void - loadFromEF(int ef, int extensionEF, int recordNumber, - Message response) - { - this.ef = ef; - this.extensionEF = extensionEF; - this.recordNumber = recordNumber; - this.userResponse = response; - - phone.mSIMFileHandler.loadEFLinearFixed( - ef, recordNumber, - obtainMessage(EVENT_ADN_LOAD_DONE)); - - } - - - /** - * Resulting ArrayList<adnRecord> is placed in response.obj.result - * or response.obj.exception is set - */ - void - loadAllFromEF(int ef, int extensionEF, - Message response) - { - this.ef = ef; - this.extensionEF = extensionEF; - this.userResponse = response; - - phone.mSIMFileHandler.loadEFLinearFixedAll( - ef, - obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); - - } - - /** - * Write adn to a EF SIM record - * It will get the record size of EF record and compose hex adn array - * then write the hex array to EF record - * - * @param adn is set with alphaTag and phoneNubmer - * @param ef EF fileid - * @param extensionEF extension EF fileid - * @param recordNumber 1-based record index - * @param pin2 for CHV2 operations, must be null if pin2 is not needed - * @param response will be sent to its handler when completed - */ - void - updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber, - String pin2, Message response) - { - this.ef = ef; - this.extensionEF = extensionEF; - this.recordNumber = recordNumber; - this.userResponse = response; - this.pin2 = pin2; - - phone.mSIMFileHandler.getEFLinearRecordSize( ef, - obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn)); - } - - //***** Overridden from Handler - - public void - handleMessage(Message msg) - { - AsyncResult ar; - byte data[]; - AdnRecord adn; - - try { - switch (msg.what) { - case EVENT_EF_LINEAR_RECORD_SIZE_DONE: - ar = (AsyncResult)(msg.obj); - adn = (AdnRecord)(ar.userObj); - - if (ar.exception != null) { - throw new RuntimeException("get EF record size failed", - ar.exception); - } - - int[] recordSize = (int[])ar.result; - // recordSize is int[3] array - // int[0] is the record length - // int[1] is the total length of the EF file - // int[2] is the number of records in the EF file - // So int[0] * int[2] = int[1] - if (recordSize.length != 3 || recordNumber > recordSize[2]) { - throw new RuntimeException("get wrong EF record size format", - ar.exception); - } - - data = adn.buildAdnString(recordSize[0]); - - if(data == null) { - throw new RuntimeException("worong ADN format", - ar.exception); - } - - phone.mSIMFileHandler.updateEFLinearFixed(ef, recordNumber, - data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); - - pendingExtLoads = 1; - - break; - case EVENT_UPDATE_RECORD_DONE: - ar = (AsyncResult)(msg.obj); - if (ar.exception != null) { - throw new RuntimeException("update EF adn record failed", - ar.exception); - } - pendingExtLoads = 0; - result = null; - break; - case EVENT_ADN_LOAD_DONE: - ar = (AsyncResult)(msg.obj); - data = (byte[])(ar.result); - - if (ar.exception != null) { - throw new RuntimeException("load failed", ar.exception); - } - - if (false) { - Log.d(LOG_TAG,"ADN EF: 0x" - + Integer.toHexString(ef) - + ":" + recordNumber - + "\n" + SimUtils.bytesToHexString(data)); - } - - adn = new AdnRecord(ef, recordNumber, data); - result = adn; - - if (adn.hasExtendedRecord()) { - // If we have a valid value in the ext record field, - // we're not done yet: we need to read the corresponding - // ext record and append it - - pendingExtLoads = 1; - - phone.mSIMFileHandler.loadEFLinearFixed( - extensionEF, adn.extRecord, - obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); - } - break; - - case EVENT_EXT_RECORD_LOAD_DONE: - ar = (AsyncResult)(msg.obj); - data = (byte[])(ar.result); - adn = (AdnRecord)(ar.userObj); - - if (ar.exception != null) { - throw new RuntimeException("load failed", ar.exception); - } - - Log.d(LOG_TAG,"ADN extention EF: 0x" - + Integer.toHexString(extensionEF) - + ":" + adn.extRecord - + "\n" + SimUtils.bytesToHexString(data)); - - adn.appendExtRecord(data); - - pendingExtLoads--; - // result should have been set in - // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE - break; - - case EVENT_ADN_LOAD_ALL_DONE: - ar = (AsyncResult)(msg.obj); - ArrayList datas = (ArrayList)(ar.result); - - if (ar.exception != null) { - throw new RuntimeException("load failed", ar.exception); - } - - adns = new ArrayList(datas.size()); - result = adns; - pendingExtLoads = 0; - - for(int i = 0, s = datas.size() ; i < s ; i++) { - adn = new AdnRecord(ef, 1 + i, datas.get(i)); - adns.add(adn); - - if (adn.hasExtendedRecord()) { - // If we have a valid value in the ext record field, - // we're not done yet: we need to read the corresponding - // ext record and append it - - pendingExtLoads++; - - phone.mSIMFileHandler.loadEFLinearFixed( - extensionEF, adn.extRecord, - obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); - } - } - break; - } - } catch (RuntimeException exc) { - if (userResponse != null) { - AsyncResult.forMessage(userResponse) - .exception = exc; - userResponse.sendToTarget(); - // Loading is all or nothing--either every load succeeds - // or we fail the whole thing. - userResponse = null; - } - return; - } - - if (userResponse != null && pendingExtLoads == 0) { - AsyncResult.forMessage(userResponse).result - = result; - - userResponse.sendToTarget(); - userResponse = null; - } - } - - -} - -/** - * - * Used to load or store ADNs (Abbreviated Dialing Numbers). - * - * {@hide} - * - */ -public class AdnRecord implements Parcelable -{ - static final String LOG_TAG = "GSM"; - - //***** Instance Variables - - String alphaTag = ""; - String number = ""; - int extRecord = 0xff; - int efid; // or 0 if none - int recordNumber; // or 0 if none - - - //***** Constants - - // In an ADN record, everything but the alpha identifier - // is in a footer that's 14 bytes - static final int FOOTER_SIZE_BYTES = 14; - - // Maximum size of the un-extended number field - static final int MAX_NUMBER_SIZE_BYTES = 11; - - static final int EXT_RECORD_LENGTH_BYTES = 13; - static final int EXT_RECORD_TYPE_ADDITIONAL_DATA = 2; - static final int EXT_RECORD_TYPE_MASK = 3; - static final int MAX_EXT_CALLED_PARTY_LENGTH = 0xa; - - // ADN offset - static final int ADN_BCD_NUMBER_LENGTH = 0; - static final int ADN_TON_AND_NPI = 1; - static final int ADN_DAILING_NUMBER_START = 2; - static final int ADN_DAILING_NUMBER_END = 11; - static final int ADN_CAPABILITY_ID = 12; - static final int ADN_EXTENSION_ID = 13; - - //***** Static Methods - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() - { - public AdnRecord createFromParcel(Parcel source) - { - int efid; - int recordNumber; - String alphaTag; - String number; - - efid = source.readInt(); - recordNumber = source.readInt(); - alphaTag = source.readString(); - number = source.readString(); - - return new AdnRecord(efid, recordNumber, alphaTag, number); - } - - public AdnRecord[] newArray(int size) - { - return new AdnRecord[size]; - } - }; - - - //***** Constructor - public - AdnRecord (byte[] record) - { - this(0, 0, record); - } - - public - AdnRecord (int efid, int recordNumber, byte[] record) - { - this.efid = efid; - this.recordNumber = recordNumber; - parseRecord(record); - } - - public - AdnRecord (String alphaTag, String number) - { - this(0, 0, alphaTag, number); - } - - public - AdnRecord (int efid, int recordNumber, String alphaTag, String number) - { - this.efid = efid; - this.recordNumber = recordNumber; - this.alphaTag = alphaTag; - this.number = number; - } - - //***** Instance Methods - - public String getAlphaTag() - { - return alphaTag; - } - - public String getNumber() - { - return number; - } - - public String toString() - { - return "ADN Record '" + alphaTag + "' '" + number + "'"; - } - - public boolean isEmpty() - { - return alphaTag.equals("") && number.equals(""); - } - - public boolean hasExtendedRecord() - { - return extRecord != 0 && extRecord != 0xff; - } - - public boolean isEqual(AdnRecord adn) { - return ( alphaTag.equals(adn.getAlphaTag()) && - number.equals(adn.getNumber()) ); - } - //***** Parcelable Implementation - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) - { - dest.writeInt(efid); - dest.writeInt(recordNumber); - dest.writeString(alphaTag); - dest.writeString(number); - } - - /** - * Build adn hex byte array based on record size - * The format of byte array is defined in 51.011 10.5.1 - * - * @param recordSize is the size X of EF record - * @return hex byte[recordSize] to be written to EF record - * return nulll for wrong format of dialing nubmer or tag - */ - public byte[] buildAdnString(int recordSize) { - byte[] bcdNumber; - byte[] byteTag; - byte[] adnString = null; - int footerOffset = recordSize - FOOTER_SIZE_BYTES; - - if (number == null || number.equals("") || - alphaTag == null || alphaTag.equals("")) { - - Log.w(LOG_TAG, "[buildAdnString] Empty alpha tag or number"); - adnString = new byte[recordSize]; - for (int i = 0; i < recordSize; i++) { - adnString[i] = (byte) 0xFF; - } - } else if (number.length() - > (ADN_DAILING_NUMBER_END - ADN_DAILING_NUMBER_START + 1) * 2) { - Log.w(LOG_TAG, - "[buildAdnString] Max length of dailing number is 20"); - } else if (alphaTag.length() > footerOffset) { - Log.w(LOG_TAG, - "[buildAdnString] Max length of tag is " + footerOffset); - } else { - - adnString = new byte[recordSize]; - for (int i = 0; i < recordSize; i++) { - adnString[i] = (byte) 0xFF; - } - - bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(number); - - System.arraycopy(bcdNumber, 0, adnString, - footerOffset + ADN_TON_AND_NPI, bcdNumber.length); - - adnString[footerOffset + ADN_BCD_NUMBER_LENGTH] - = (byte) (bcdNumber.length); - adnString[footerOffset + ADN_CAPABILITY_ID] - = (byte) 0xFF; // Capacility Id - adnString[footerOffset + ADN_EXTENSION_ID] - = (byte) 0xFF; // Extension Record Id - - byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag); - System.arraycopy(byteTag, 0, adnString, 0, byteTag.length); - - } - - return adnString; - } - - /** - * See TS 51.011 10.5.10 - */ - public void - appendExtRecord (byte[] extRecord) { - try { - if (extRecord.length != EXT_RECORD_LENGTH_BYTES) { - return; - } - - if ((extRecord[0] & EXT_RECORD_TYPE_MASK) - != EXT_RECORD_TYPE_ADDITIONAL_DATA - ) { - return; - } - - if ((0xff & extRecord[1]) > MAX_EXT_CALLED_PARTY_LENGTH) { - // invalid or empty record - return; - } - - number += PhoneNumberUtils.calledPartyBCDFragmentToString( - extRecord, 2, 0xff & extRecord[1]); - - // We don't support ext record chaining. - - } catch (RuntimeException ex) { - - - - - Log.w(LOG_TAG, "Error parsing AdnRecord ext record", ex); - } - } - - //***** Private Methods - - /** - * alphaTag and number are set to null on invalid format - */ - private void - parseRecord(byte[] record) { - try { - alphaTag = SimUtils.adnStringFieldToString( - record, 0, record.length - FOOTER_SIZE_BYTES); - - int footerOffset = record.length - FOOTER_SIZE_BYTES; - - int numberLength = 0xff & record[footerOffset]; - - if (numberLength > MAX_NUMBER_SIZE_BYTES) { - // Invalid number length - number = ""; - return; - } - - // Please note 51.011 10.5.1: - // - // "If the Dialling Number/SSC String does not contain - // a dialling number, e.g. a control string deactivating - // a service, the TON/NPI byte shall be set to 'FF' by - // the ME (see note 2)." - - number = PhoneNumberUtils.calledPartyBCDToString( - record, footerOffset + 1, numberLength); - - - extRecord = 0xff & record[record.length - 1]; - - } catch (RuntimeException ex) { - Log.w(LOG_TAG, "Error parsing AdnRecord", ex); - number = ""; - alphaTag = ""; - } - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java b/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java deleted file mode 100644 index 8e14b4339ff24eeaca17e2e224b06f14c9e627c4..0000000000000000000000000000000000000000 --- a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java +++ /dev/null @@ -1,367 +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; - -import android.content.Context; -import android.os.RegistrantList; -import android.os.Registrant; -import android.os.Handler; -import android.os.AsyncResult; -import android.os.SystemProperties; -import android.provider.Checkin; -import android.util.Config; -import android.util.Log; - -/** - * {@hide} - */ -public abstract class BaseCommands implements CommandsInterface -{ - static final String LOG_TAG = "GSM"; - - //***** Instance Variables - protected Context mContext; - protected RadioState mState = RadioState.RADIO_UNAVAILABLE; - protected Object mStateMonitor = new Object(); - - protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList(); - protected RegistrantList mOnRegistrants = new RegistrantList(); - protected RegistrantList mAvailRegistrants = new RegistrantList(); - protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList(); - protected RegistrantList mNotAvailRegistrants = new RegistrantList(); - protected RegistrantList mSIMReadyRegistrants = new RegistrantList(); - protected RegistrantList mSIMLockedRegistrants = new RegistrantList(); - protected RegistrantList mCallStateRegistrants = new RegistrantList(); - protected RegistrantList mNetworkStateRegistrants = new RegistrantList(); - protected RegistrantList mPDPRegistrants = new RegistrantList(); - protected Registrant mSMSRegistrant; - protected Registrant mNITZTimeRegistrant; - protected Registrant mSignalStrengthRegistrant; - protected Registrant mUSSDRegistrant; - protected Registrant mSmsOnSimRegistrant; - /** Registrant for handling SMS Status Reports */ - protected Registrant mSmsStatusRegistrant; - /** Registrant for handling Supplementary Service Notifications */ - protected Registrant mSsnRegistrant; - protected Registrant mStkSessionEndRegistrant; - protected Registrant mStkProCmdRegistrant; - protected Registrant mStkEventRegistrant; - protected Registrant mStkCallSetUpRegistrant; - /** Registrant for handling SIM SMS storage full messages */ - protected Registrant mSimSmsFullRegistrant; - /** Registrant for handling SIM Refresh notifications */ - protected Registrant mSimRefreshRegistrant; - /** Registrant for handling RING notifications */ - protected Registrant mRingRegistrant; - /** Registrant for handling RESTRICTED STATE changed notification */ - protected Registrant mRestrictedStateRegistrant; - - public BaseCommands(Context context) { - mContext = context; // May be null (if so we won't log statistics) - } - - //***** CommandsInterface implementation - - public RadioState - getRadioState() - { - return mState; - } - - - public void - registerForRadioStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mRadioStateChangedRegistrants.add(r); - r.notifyRegistrant(); - } - } - - public void - registerForOn(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mOnRegistrants.add(r); - - if (mState.isOn()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - - public void - registerForAvailable(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mAvailRegistrants.add(r); - - if (mState.isAvailable()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForNotAvailable(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mNotAvailRegistrants.add(r); - - if (!mState.isAvailable()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForOffOrNotAvailable(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mOffOrNotAvailRegistrants.add(r); - - if (mState == RadioState.RADIO_OFF || !mState.isAvailable()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - - /** Any transition into SIM_READY */ - public void - registerForSIMReady(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mSIMReadyRegistrants.add(r); - - if (mState.isSIMReady()) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForSIMLockedOrAbsent(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - synchronized (mStateMonitor) { - mSIMLockedRegistrants.add(r); - - if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } - } - - public void - registerForCallStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - mCallStateRegistrants.add(r); - } - - public void - registerForNetworkStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - mNetworkStateRegistrants.add(r); - } - - public void - registerForPDPStateChanged(Handler h, int what, Object obj) - { - Registrant r = new Registrant (h, what, obj); - - mPDPRegistrants.add(r); - } - - public void - setOnNewSMS(Handler h, int what, Object obj) - { - mSMSRegistrant = new Registrant (h, what, obj); - } - - public void - setOnSmsOnSim(Handler h, int what, Object obj) - { - mSmsOnSimRegistrant = new Registrant (h, what, obj); - } - - public void setOnSmsStatus(Handler h, int what, Object obj) { - mSmsStatusRegistrant = new Registrant (h, what, obj); - } - - public void - setOnSignalStrengthUpdate(Handler h, int what, Object obj) - { - mSignalStrengthRegistrant = new Registrant (h, what, obj); - } - - public void - setOnNITZTime(Handler h, int what, Object obj) - { - mNITZTimeRegistrant = new Registrant (h, what, obj); - } - - public void - setOnUSSD(Handler h, int what, Object obj) - { - mUSSDRegistrant = new Registrant (h, what, obj); - } - - public void - setOnSuppServiceNotification(Handler h, int what, Object obj) - { - mSsnRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkSessionEnd(Handler h, int what, Object obj) - { - mStkSessionEndRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkProactiveCmd(Handler h, int what, Object obj) - { - mStkProCmdRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkEvent(Handler h, int what, Object obj) - { - mStkEventRegistrant = new Registrant (h, what, obj); - } - - public void - setOnStkCallSetUp(Handler h, int what, Object obj) - { - mStkCallSetUpRegistrant = new Registrant (h, what, obj); - } - - public void setOnSimSmsFull(Handler h, int what, Object obj) { - mSimSmsFullRegistrant = new Registrant (h, what, obj); - } - - public void setOnSimRefresh(Handler h, int what, Object obj) { - mSimRefreshRegistrant = new Registrant (h, what, obj); - } - - public void setOnCallRing(Handler h, int what, Object obj) { - mRingRegistrant = new Registrant (h, what, obj); - } - - public void - setOnRestrictedStateChanged(Handler h, int what, Object obj) - { - mRestrictedStateRegistrant = new Registrant (h, what, obj); - } - - //***** Protected Methods - /** - * Store new RadioState and send notification based on the changes - * - * This function is called only by RIL.java when receiving unsolicited - * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED - * - * RadioState has 5 values : RADIO_OFF, RADIO_UNAVAILABLE, SIM_NOT_READY, - * SIM_LOCKED_OR_ABSENT, and SIM_READY. - * - * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED - */ - protected void setRadioState(RadioState newState) { - RadioState oldState; - - synchronized (mStateMonitor) { - if (Config.LOGV) { - Log.v(LOG_TAG, "setRadioState old: " + mState - + " new " + newState); - } - - oldState = mState; - mState = newState; - - if (oldState == mState) { - // no state transition - return; - } - - if (mContext != null && - newState == RadioState.RADIO_UNAVAILABLE && - oldState != RadioState.RADIO_OFF) { - Checkin.updateStats(mContext.getContentResolver(), - Checkin.Stats.Tag.PHONE_RADIO_RESETS, 1, 0.0); - } - - mRadioStateChangedRegistrants.notifyRegistrants(); - - if (mState.isAvailable() && !oldState.isAvailable()) { - Log.d(LOG_TAG,"Notifying: radio available"); - mAvailRegistrants.notifyRegistrants(); - onRadioAvailable(); - } - - if (!mState.isAvailable() && oldState.isAvailable()) { - Log.d(LOG_TAG,"Notifying: radio not available"); - mNotAvailRegistrants.notifyRegistrants(); - } - - if (mState.isSIMReady() && !oldState.isSIMReady()) { - Log.d(LOG_TAG,"Notifying: SIM ready"); - mSIMReadyRegistrants.notifyRegistrants(); - } - - if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { - Log.d(LOG_TAG,"Notifying: SIM locked or absent"); - mSIMLockedRegistrants.notifyRegistrants(); - } - - if (mState.isOn() && !oldState.isOn()) { - Log.d(LOG_TAG,"Notifying: Radio On"); - mOnRegistrants.notifyRegistrants(); - } - - if ((!mState.isOn() || !mState.isAvailable()) - && !((!oldState.isOn() || !oldState.isAvailable())) - ) { - Log.d(LOG_TAG,"Notifying: radio off or not available"); - mOffOrNotAvailRegistrants.notifyRegistrants(); - } - } - } - - protected void - onRadioAvailable() - { - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java old mode 100644 new mode 100755 index f93c72469d0ed5d7a8a067023532276594f7a740..a2d3c5e380470e18848cdd512182c0836dbd8834 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -16,18 +16,6 @@ package com.android.internal.telephony.gsm; -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; @@ -41,26 +29,47 @@ import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; +import android.provider.Settings; import android.provider.Telephony; 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 static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; + +import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.IccSmsInterfaceManager; 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.PhoneProxy; import com.android.internal.telephony.PhoneSubInfo; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.gsm.SimException; +import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.gsm.stk.StkService; import com.android.internal.telephony.test.SimulatedRadioControl; +import com.android.internal.telephony.IccVmNotSupportedException; import java.io.IOException; import java.net.InetSocketAddress; @@ -77,40 +86,28 @@ public class GSMPhone extends PhoneBase { // from this file will go into the radio log rather than the main // log. (Use "adb logcat -b radio" to see them.) static final String LOG_TAG = "GSM"; - private static final boolean LOCAL_DEBUG = false; + private static final boolean LOCAL_DEBUG = true; - // Key used to read and write the saved network selection value - public static final String NETWORK_SELECTION_KEY = "network_selection_key"; - // Key used to read/write "disable data connection on boot" pref (used for testing) - public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; // Key used to read/write current ciphering state 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"; - // Key used to read/write "disable DNS server check" pref (used for testing) - public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key"; //***** Instance Variables - - CallTracker mCT; - ServiceStateTracker mSST; - CommandsInterface mCM; - SMSDispatcher mSMS; - DataConnectionTracker mDataConnection; - SIMFileHandler mSIMFileHandler; + GsmCallTracker mCT; + GsmServiceStateTracker mSST; + GsmSMSDispatcher mSMS; + GsmDataConnectionTracker mDataConnection; SIMRecords mSIMRecords; - GsmSimCard mSimCard; + SimCard mSimCard; StkService mStkService; MyHandler h; ArrayList mPendingMMIs = new ArrayList(); SimPhoneBookInterfaceManager mSimPhoneBookIntManager; SimSmsInterfaceManager mSimSmsIntManager; PhoneSubInfo mSubInfo; - boolean mDnsCheckDisabled = false; Registrant mPostDialHandler; @@ -129,44 +126,17 @@ public class GSMPhone extends PhoneBase { private String mImeiSv; private String mVmNumber; - //***** Event Constants - - static final int EVENT_RADIO_AVAILABLE = 1; - /** Supplemnetary Service Notification received. */ - static final int EVENT_SSN = 2; - static final int EVENT_SIM_RECORDS_LOADED = 3; - static final int EVENT_MMI_DONE = 4; - static final int EVENT_RADIO_ON = 5; - static final int EVENT_GET_BASEBAND_VERSION_DONE = 6; - static final int EVENT_USSD = 7; - static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; - static final int EVENT_GET_IMEI_DONE = 9; - static final int EVENT_GET_IMEISV_DONE = 10; - static final int EVENT_GET_SIM_STATUS_DONE = 11; - static final int EVENT_SET_CALL_FORWARD_DONE = 12; - static final int EVENT_GET_CALL_FORWARD_DONE = 13; - static final int EVENT_CALL_RING = 14; - // Used to intercept the carriere selection calls so that - // we can save the values. - static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15; - 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 public - GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) - { + GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) { this(context,ci,notifier, false); } public - GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) - { + GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { super(notifier, context, unitTestMode); - h = new MyHandler(); mCM = ci; @@ -174,34 +144,31 @@ public class GSMPhone extends PhoneBase { mSimulatedRadioControl = (SimulatedRadioControl) ci; } - mCT = new CallTracker(this); - mSST = new ServiceStateTracker (this); - mSMS = new SMSDispatcher(this); - mSIMFileHandler = new SIMFileHandler(this); + mCM.setPhoneType(RILConstants.GSM_PHONE); + mCT = new GsmCallTracker(this); + mSST = new GsmServiceStateTracker (this); + mSMS = new GsmSMSDispatcher(this); + mIccFileHandler = new SIMFileHandler(this); mSIMRecords = new SIMRecords(this); - mDataConnection = new DataConnectionTracker (this); - mSimCard = new GsmSimCard(this); + mDataConnection = new GsmDataConnectionTracker (this); + mSimCard = new SimCard(this); if (!unitTestMode) { mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this); mSimSmsIntManager = new SimSmsInterfaceManager(this); mSubInfo = new PhoneSubInfo(this); } mStkService = StkService.getInstance(mCM, mSIMRecords, mContext, - mSIMFileHandler, mSimCard); - + (SIMFileHandler)mIccFileHandler, mSimCard); + mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); mSIMRecords.registerForRecordsLoaded(h, EVENT_SIM_RECORDS_LOADED, null); - mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, - null); + mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mCM.registerForOn(h, EVENT_RADIO_ON, null); mCM.setOnUSSD(h, EVENT_USSD, null); mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); mCM.setOnCallRing(h, EVENT_CALL_RING, null); mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); - if (false) { try { //debugSocket = new LocalServerSocket("com.android.internal.telephony.debug"); @@ -221,7 +188,7 @@ public class GSMPhone extends PhoneBase { mCM.resetRadio(null); sock.close(); } catch (IOException ex) { - Log.w(LOG_TAG, + Log.w(LOG_TAG, "Exception accepting socket", ex); } } @@ -235,13 +202,64 @@ public class GSMPhone extends PhoneBase { Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex); } } + + //Change the system setting + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE); + } + + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + //Unregister from all former registered events + mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE + mSIMRecords.unregisterForRecordsLoaded(h); //EVENT_SIM_RECORDS_LOADED + mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(h); //EVENT_RADIO_ON + mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnUSSD(h); + mCM.unSetOnSuppServiceNotification(h); + mCM.unSetOnCallRing(h); + + mPendingMMIs.clear(); + + //Force all referenced classes to unregister their former registered events + mStkService.dispose(); + mCT.dispose(); + mDataConnection.dispose(); + mSST.dispose(); + mIccFileHandler.dispose(); // instance of SimFileHandler + mSIMRecords.dispose(); + mSimCard.dispose(); + mSimPhoneBookIntManager.dispose(); + mSimSmsIntManager.dispose(); + mSubInfo.dispose(); + } } - + + public void removeReferences() { + this.mSimulatedRadioControl = null; + this.mStkService = null; + this.mSimPhoneBookIntManager = null; + this.mSimSmsIntManager = null; + this.mSMS = null; + this.mSubInfo = null; + this.mSIMRecords = null; + this.mIccFileHandler = null; + this.mSimCard = null; + this.mDataConnection = null; + this.mCT = null; + this.mSST = null; + } + + protected void finalize() { + if(LOCAL_DEBUG) Log.d(LOG_TAG, "GSMPhone finalized"); + } + + //***** Overridden from Phone - public ServiceState - getServiceState() - { + public ServiceState + getServiceState() { return mSST.ss; } @@ -249,15 +267,13 @@ public class GSMPhone extends PhoneBase { return mSST.cellLoc; } - public Phone.State - getState() - { + public Phone.State + getState() { return mCT.state; } public String - getPhoneName() - { + getPhoneName() { return "GSM"; } @@ -270,14 +286,12 @@ public class GSMPhone extends PhoneBase { } public int - getSignalStrengthASU() - { + getSignalStrengthASU() { return mSST.rssi == 99 ? -1 : mSST.rssi; } public boolean - getMessageWaitingIndicator() - { + getMessageWaitingIndicator() { return mSIMRecords.getVoiceMessageWaiting(); } @@ -287,8 +301,7 @@ public class GSMPhone extends PhoneBase { } public List - getPendingMmiCodes() - { + getPendingMmiCodes() { return mPendingMMIs; } @@ -303,33 +316,38 @@ public class GSMPhone extends PhoneBase { // we report data connected ret = DataState.CONNECTED; + } else if (mSST == null) { + // Radio Technology Change is ongoning, dispose() and removeReferences() have + // already been called + + ret = DataState.DISCONNECTED; } else if (mSST.getCurrentGprsState() != ServiceState.STATE_IN_SERVICE) { // If we're out of service, open TCP sockets may still work // but no data will flow ret = DataState.DISCONNECTED; } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ - switch (mDataConnection.state) { - case FAILED: - case IDLE: - ret = DataState.DISCONNECTED; - break; + switch (mDataConnection.getState()) { + case FAILED: + case IDLE: + ret = DataState.DISCONNECTED; + break; - case CONNECTED: - case DISCONNECTING: - if ( mCT.state != Phone.State.IDLE - && !mSST.isConcurrentVoiceAndData()) { - ret = DataState.SUSPENDED; - } else { - ret = DataState.CONNECTED; - } - break; + case CONNECTED: + case DISCONNECTING: + if ( mCT.state != Phone.State.IDLE + && !mSST.isConcurrentVoiceAndData()) { + ret = DataState.SUSPENDED; + } else { + ret = DataState.CONNECTED; + } + break; - case INITING: - case CONNECTING: - case SCANNING: - ret = DataState.CONNECTING; - break; + case INITING: + case CONNECTING: + case SCANNING: + ret = DataState.CONNECTING; + break; } } @@ -340,19 +358,18 @@ public class GSMPhone extends PhoneBase { DataActivityState ret = DataActivityState.NONE; if (mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE) { - switch (mDataConnection.activity) { - - case DATAIN: - ret = DataActivityState.DATAIN; - break; + switch (mDataConnection.getActivity()) { + case DATAIN: + ret = DataActivityState.DATAIN; + break; - case DATAOUT: - ret = DataActivityState.DATAOUT; - break; + case DATAOUT: + ret = DataActivityState.DATAOUT; + break; - case DATAINANDOUT: - ret = DataActivityState.DATAINANDOUT; - break; + case DATAINANDOUT: + ret = DataActivityState.DATAINANDOUT; + break; } } @@ -371,15 +388,13 @@ public class GSMPhone extends PhoneBase { * changes to call state (including Phone and Connection changes). */ /*package*/ void - notifyCallStateChanged() - { + notifyCallStateChanged() { /* we'd love it if this was package-scoped*/ super.notifyCallStateChangedP(); } /*package*/ void - notifyNewRingingConnection(Connection c) - { + notifyNewRingingConnection(Connection c) { /* we'd love it if this was package-scoped*/ super.notifyNewRingingConnectionP(c); } @@ -387,28 +402,26 @@ public class GSMPhone extends PhoneBase { /** * Notifiy registrants of a RING event. */ - void notifyIncomingRing() { + void notifyIncomingRing() { AsyncResult ar = new AsyncResult(null, this, null); mIncomingRingRegistrants.notifyRegistrants(ar); } - + /*package*/ void - notifyDisconnect(Connection cn) - { + notifyDisconnect(Connection cn) { mDisconnectRegistrants.notifyResult(cn); } void notifyUnknownConnection() { mUnknownConnectionRegistrants.notifyResult(this); } - + void notifySuppServiceFailed(SuppService code) { mSuppServiceFailedRegistrants.notifyResult(code); } /*package*/ void - notifyServiceStateChanged(ServiceState ss) - { + notifyServiceStateChanged(ServiceState ss) { super.notifyServiceStateChangedP(ss); } @@ -418,55 +431,38 @@ public class GSMPhone extends PhoneBase { } /*package*/ void - notifySignalStrength() - { + notifySignalStrength() { mNotifier.notifySignalStrength(this); } - /*package*/ void - notifyDataConnection(String reason) { - mNotifier.notifyDataConnection(this, reason); - } - /*package*/ void notifyDataConnectionFailed(String reason) { mNotifier.notifyDataConnectionFailed(this, reason); } /*package*/ void - notifyDataActivity() { - mNotifier.notifyDataActivity(this); - } - - /*package*/ void - updateMessageWaitingIndicator(boolean mwi) - { + updateMessageWaitingIndicator(boolean mwi) { // this also calls notifyMessageWaitingIndicator() mSIMRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); } - /*package*/ void - notifyMessageWaitingIndicator() - { + public void + notifyMessageWaitingIndicator() { mNotifier.notifyMessageWaitingChanged(this); } - /*package*/ void + public void notifyCallForwardingIndicator() { mNotifier.notifyCallForwardingChanged(this); } + // override for allowing access from other classes of this package /** - * Set a system property, unless we're in unit test mode + * {@inheritDoc} */ - - /*package*/ void - setSystemProperty(String property, String value) - { - if(getUnitTestMode()) { - return; - } - SystemProperties.set(property, value); + public final void + setSystemProperty(String property, String value) { + super.setSystemProperty(property, value); } public void registerForSuppServiceNotification( @@ -480,71 +476,57 @@ public class GSMPhone extends PhoneBase { if (mSsnRegistrants.size() == 0) mCM.setSuppServiceNotifications(false, null); } - public void - acceptCall() throws CallStateException - { + public void + acceptCall() throws CallStateException { mCT.acceptCall(); } - public void - rejectCall() throws CallStateException - { + public void + rejectCall() throws CallStateException { mCT.rejectCall(); } public void - switchHoldingAndActive() throws CallStateException - { + switchHoldingAndActive() throws CallStateException { mCT.switchWaitingOrHoldingAndActive(); } - - public boolean canConference() - { + public boolean canConference() { return mCT.canConference(); } - public boolean canDial() - { + public boolean canDial() { return mCT.canDial(); } - public void conference() throws CallStateException - { + public void conference() throws CallStateException { mCT.conference(); } - public void clearDisconnected() - { - + public void clearDisconnected() { mCT.clearDisconnected(); } - public boolean canTransfer() - { + public boolean canTransfer() { return mCT.canTransfer(); } - public void explicitCallTransfer() throws CallStateException - { + public void explicitCallTransfer() throws CallStateException { mCT.explicitCallTransfer(); } - public Call - getForegroundCall() - { + public GsmCall + getForegroundCall() { return mCT.foregroundCall; } - public Call - getBackgroundCall() - { + public GsmCall + getBackgroundCall() { return mCT.backgroundCall; } - public Call - getRingingCall() - { + public GsmCall + getRingingCall() { return mCT.ringingCall; } @@ -554,7 +536,7 @@ public class GSMPhone extends PhoneBase { return false; } - if (getRingingCall().getState() != Call.State.IDLE) { + if (getRingingCall().getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 0: rejectCall"); try { mCT.rejectCall(); @@ -563,7 +545,7 @@ public class GSMPhone extends PhoneBase { "reject failed", e); notifySuppServiceFailed(Phone.SuppService.REJECT); } - } else if (getBackgroundCall().getState() != Call.State.IDLE) { + } else if (getBackgroundCall().getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 0: hangupWaitingOrBackground"); mCT.hangupWaitingOrBackground(); @@ -580,21 +562,21 @@ public class GSMPhone extends PhoneBase { return false; } - GSMCall call = (GSMCall) getForegroundCall(); + GsmCall call = (GsmCall) getForegroundCall(); try { if (len > 1) { char ch = dialString.charAt(1); int callIndex = ch - '0'; - if (callIndex >= 1 && callIndex <= CallTracker.MAX_CONNECTIONS) { + if (callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 1: hangupConnectionByIndex " + callIndex); mCT.hangupConnectionByIndex(call, callIndex); } } else { - if (call.getState() != Call.State.IDLE) { + if (call.getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 1: hangup foreground"); //mCT.hangupForegroundResumeBackground(); @@ -622,16 +604,16 @@ public class GSMPhone extends PhoneBase { return false; } - GSMCall call = (GSMCall) getForegroundCall(); + GsmCall call = (GsmCall) getForegroundCall(); if (len > 1) { try { char ch = dialString.charAt(1); int callIndex = ch - '0'; - GSMConnection conn = mCT.getConnectionByIndex(call, callIndex); - + GsmConnection conn = mCT.getConnectionByIndex(call, callIndex); + // gsm index starts at 1, up to 5 connections in a call, - if (conn != null && callIndex >= 1 && callIndex <= CallTracker.MAX_CONNECTIONS) { + if (conn != null && callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 2: separate call "+ callIndex); mCT.separate(conn); @@ -647,7 +629,7 @@ public class GSMPhone extends PhoneBase { } } else { try { - if (getRingingCall().getState() != Call.State.IDLE) { + if (getRingingCall().getState() != GsmCall.State.IDLE) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 2: accept ringing call"); mCT.acceptCall(); @@ -756,9 +738,9 @@ public class GSMPhone extends PhoneBase { } boolean isInCall() { - Call.State foregroundCallState = getForegroundCall().getState(); - Call.State backgroundCallState = getBackgroundCall().getState(); - Call.State ringingCallState = getRingingCall().getState(); + GsmCall.State foregroundCallState = getForegroundCall().getState(); + GsmCall.State backgroundCallState = getBackgroundCall().getState(); + GsmCall.State ringingCallState = getRingingCall().getState(); return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || @@ -797,15 +779,15 @@ public class GSMPhone extends PhoneBase { public boolean handlePinMmi(String dialString) { GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this); - + if (mmi != null && mmi.isPinCommand()) { mPendingMMIs.add(mmi); mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); mmi.processCode(); return true; } - - return false; + + return false; } public void sendUssdResponse(String ussdMessge) { @@ -814,11 +796,11 @@ public class GSMPhone extends PhoneBase { mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); mmi.sendUssd(ussdMessge); } - + public void sendDtmf(char c) { if (!PhoneNumberUtils.is12Key(c)) { - Log.e(LOG_TAG, + Log.e(LOG_TAG, "sendDtmf called with invalid character '" + c + "'"); } else { if (mCT.state == Phone.State.OFFHOOK) { @@ -887,7 +869,7 @@ public class GSMPhone extends PhoneBase { com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); } - return ret; + return ret; } public String getDeviceId() { @@ -898,11 +880,21 @@ public class GSMPhone extends PhoneBase { return mImeiSv; } + public String getEsn() { + Log.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method"); + return "0"; + } + + public String getMeid() { + Log.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method"); + return "0"; + } + public String getSubscriberId() { return mSIMRecords.imsi; } - public String getSimSerialNumber() { + public String getIccSerialNumber() { return mSIMRecords.iccid; } @@ -939,37 +931,35 @@ public class GSMPhone extends PhoneBase { private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { switch (commandInterfaceCFReason) { - case CF_REASON_UNCONDITIONAL: - case CF_REASON_BUSY: - case CF_REASON_NO_REPLY: - case CF_REASON_NOT_REACHABLE: - case CF_REASON_ALL: - case CF_REASON_ALL_CONDITIONAL: - return true; - default: - return false; + case CF_REASON_UNCONDITIONAL: + case CF_REASON_BUSY: + case CF_REASON_NO_REPLY: + case CF_REASON_NOT_REACHABLE: + case CF_REASON_ALL: + case CF_REASON_ALL_CONDITIONAL: + return true; + default: + return false; } } private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { switch (commandInterfaceCFAction) { - case CF_ACTION_DISABLE: - case CF_ACTION_ENABLE: - case CF_ACTION_REGISTRATION: - case CF_ACTION_ERASURE: - return true; - default: - return false; + case CF_ACTION_DISABLE: + case CF_ACTION_ENABLE: + case CF_ACTION_REGISTRATION: + case CF_ACTION_ERASURE: + return true; + default: + return false; } } - - private boolean isCfEnable(int action) { + + protected boolean isCfEnable(int action) { return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); } - - public void getCallForwardingOption(int commandInterfaceCFReason, - Message onComplete) { - + + public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "requesting call forwarding query."); Message resp; @@ -983,14 +973,13 @@ public class GSMPhone extends PhoneBase { } public void setCallForwardingOption(int commandInterfaceCFAction, - int commandInterfaceCFReason, - String dialingNumber, - int timerSeconds, - Message onComplete) { - - if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && - (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { - + int commandInterfaceCFReason, + String dialingNumber, + int timerSeconds, + Message onComplete) { + if ( (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && + (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { + Message resp; if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { resp = h.obtainMessage(EVENT_SET_CALL_FORWARD_DONE, @@ -1006,12 +995,12 @@ public class GSMPhone extends PhoneBase { resp); } } - + public void getOutgoingCallerIdDisplay(Message onComplete) { mCM.getCLIR(onComplete); } - - public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { mCM.setCLIR(commandInterfaceCLIRMode, h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete)); @@ -1020,162 +1009,111 @@ public class GSMPhone extends PhoneBase { public void getCallWaiting(Message onComplete) { mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } - + public void setCallWaiting(boolean enable, Message onComplete) { mCM.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } - + public boolean - getSimRecordsLoaded() { + getIccRecordsLoaded() { return mSIMRecords.getRecordsLoaded(); } - public SimCard - getSimCard() { + public IccCard getIccCard() { return mSimCard; } - public void + public void getAvailableNetworks(Message response) { mCM.getAvailableNetworks(response); } /** - * Small container class used to hold information relevant to + * Small container class used to hold information relevant to * the carrier selection process. operatorNumeric can be "" - * if we are looking for automatic selection. + * if we are looking for automatic selection. */ private static class NetworkSelectMessage { public Message message; public String operatorNumeric; } - - public void + + public void setNetworkSelectionModeAutomatic(Message response) { // wrap the response message in our own message along with - // an empty string (to indicate automatic selection) for the + // an empty string (to indicate automatic selection) for the // operator's id. NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = ""; - + // get the message Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm); - if (LOCAL_DEBUG) + if (LOCAL_DEBUG) Log.d(LOG_TAG, "wrapping and sending message to connect automatically"); mCM.setNetworkSelectionModeAutomatic(msg); } - public void + public void selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network, - Message response) { + Message response) { // wrap the response message in our own message along with // the operator's id. NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = network.operatorNumeric; - + // get the message Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm); mCM.setNetworkSelectionModeManual(network.operatorNumeric, msg); } - - /** - * Method to retrieve the saved operator id from the Shared Preferences - */ - private String getSavedNetworkSelection() { - // open the shared preferences and search with our key. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - return sp.getString(NETWORK_SELECTION_KEY, ""); - } - - /** - * Method to restore the previously saved operator id, or reset to - * automatic selection, all depending upon the value in the shared - * preferences. - */ - void restoreSavedNetworkSelection(Message response) { - // retrieve the operator id - String networkSelection = getSavedNetworkSelection(); - - // set to auto if the id is empty, otherwise select the network. - if (TextUtils.isEmpty(networkSelection)) { - mCM.setNetworkSelectionModeAutomatic(response); - } else { - mCM.setNetworkSelectionModeManual(networkSelection, response); - } - } - - public void - setPreferredNetworkType(int networkType, Message response) { - mCM.setPreferredNetworkType(networkType, response); - } - - public void - getPreferredNetworkType(Message response) { - mCM.getPreferredNetworkType(response); - } public void getNeighboringCids(Message response) { mCM.getNeighboringCids(response); } - - public void setOnPostDialCharacter(Handler h, int what, Object obj) - { + + public void setOnPostDialCharacter(Handler h, int what, Object obj) { mPostDialHandler = new Registrant(h, what, obj); } - - public void setMute(boolean muted) - { + public void setMute(boolean muted) { mCT.setMute(muted); } - - public boolean getMute() - { - return mCT.getMute(); - } - - - public void invokeOemRilRequestRaw(byte[] data, Message response) - { - mCM.invokeOemRilRequestRaw(data, response); - } - public void invokeOemRilRequestStrings(String[] strings, Message response) - { - mCM.invokeOemRilRequestStrings(strings, response); + public boolean getMute() { + return mCT.getMute(); } + /** + * @deprecated + */ public void getPdpContextList(Message response) { - mCM.getPDPContextList(response); + getDataCallList(response); } - public List getCurrentPdpList () { - return mDataConnection.getAllPdps(); + public void getDataCallList(Message response) { + mCM.getDataCallList(response); } /** - * Disables the DNS check (i.e., allows "0.0.0.0"). - * Useful for lab testing environment. - * @param b true disables the check, false enables. + * @deprecated */ - public void disableDnsCheck(boolean b) { - mDnsCheckDisabled = b; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b); - editor.commit(); + public List getCurrentPdpList() { + ArrayList connections = new ArrayList(); + ArrayList pdp_list = new ArrayList(); + + for(int n = 0; n < connections.size(); n++) { + pdp_list.add((PdpConnection) connections.get(n)); + } + + return pdp_list; } - /** - * Returns true if the DNS check is currently disabled. - */ - public boolean isDnsCheckDisabled() { - return mDnsCheckDisabled; + public List getCurrentDataConnectionList () { + return mDataConnection.getAllDataConnections(); } public void updateServiceLocation(Message response) { @@ -1190,14 +1128,6 @@ public class GSMPhone extends PhoneBase { mSST.disableLocationUpdates(); } - public void setBandMode(int bandMode, Message response) { - mCM.setBandMode(bandMode, response); - } - - public void queryAvailableBandMode(Message response) { - mCM.queryAvailableBandMode(response); - } - public boolean getDataRoamingEnabled() { return mDataConnection.getDataOnRoamingEnabled(); } @@ -1254,7 +1184,7 @@ public class GSMPhone extends PhoneBase { // check for "default"? boolean noData = mDataConnection.getDataEnabled() && getDataConnectionState() == DataState.DISCONNECTED; - return !noData && getSimCard().getState() == SimCard.State.READY && + return !noData && getIccCard().getState() == SimCard.State.READY && getServiceState().getState() == ServiceState.STATE_IN_SERVICE && (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); } @@ -1265,9 +1195,8 @@ public class GSMPhone extends PhoneBase { * @param mmi MMI that is done */ /*package*/ void - onMMIDone(GsmMmiCode mmi) - { - /* Only notify complete if it's on the pending list. + onMMIDone(GsmMmiCode mmi) { + /* Only notify complete if it's on the pending list. * Otherwise, it's already been handled (eg, previously canceled). * The exception is cancellation of an incoming USSD-REQUEST, which is * not on the list. @@ -1279,9 +1208,8 @@ public class GSMPhone extends PhoneBase { } - private void - onNetworkInitiatedUssd(GsmMmiCode mmi) - { + private void + onNetworkInitiatedUssd(GsmMmiCode mmi) { mMmiCompleteRegistrants.notifyRegistrants( new AsyncResult(null, mmi, null)); } @@ -1289,18 +1217,17 @@ public class GSMPhone extends PhoneBase { /** ussdMode is one of CommandsInterface.USSD_MODE_* */ private void - onIncomingUSSD (int ussdMode, String ussdMessage) - { + onIncomingUSSD (int ussdMode, String ussdMessage) { boolean isUssdError; boolean isUssdRequest; - - isUssdRequest + + isUssdRequest = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); - isUssdError + isUssdError = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY && ussdMode != CommandsInterface.USSD_MODE_REQUEST); - + // See comments in GsmMmiCode.java // USSD requests aren't finished until one // of these two events happen @@ -1327,7 +1254,7 @@ public class GSMPhone extends PhoneBase { // also, discard if there is no message to present if (!isUssdError && ussdMessage != null) { GsmMmiCode mmi; - mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage, + mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage, isUssdRequest, GSMPhone.this); onNetworkInitiatedUssd(mmi); @@ -1338,7 +1265,7 @@ public class GSMPhone extends PhoneBase { /** * Make sure the network knows our preferred setting. */ - private void syncClirSetting() { + protected void syncClirSetting() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); int clirSetting = sp.getInt(CLIR_KEY, -1); if (clirSetting >= 0) { @@ -1348,20 +1275,16 @@ public class GSMPhone extends PhoneBase { //***** Inner Classes - class MyHandler extends Handler - { - MyHandler() - { + class MyHandler extends Handler { + MyHandler() { } - MyHandler(Looper l) - { + MyHandler(Looper l) { super(l); } public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; Message onComplete; @@ -1422,11 +1345,10 @@ public class GSMPhone extends PhoneBase { if (ar.exception != null) { break; } - + mImeiSv = (String)ar.result; break; - case EVENT_USSD: ar = (AsyncResult)msg.obj; @@ -1441,7 +1363,7 @@ public class GSMPhone extends PhoneBase { } break; - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: // Some MMI requests (eg USSD) are not completed // within the course of a CommandsInterface request // If the radio shuts off or resets while one of these @@ -1450,10 +1372,10 @@ public class GSMPhone extends PhoneBase { for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { if (mPendingMMIs.get(i).isPendingUSSD()) { mPendingMMIs.get(i).onUssdFinishedError(); - } + } } break; - + case EVENT_SSN: ar = (AsyncResult)msg.obj; SuppServiceNotification not = (SuppServiceNotification) ar.result; @@ -1474,7 +1396,7 @@ public class GSMPhone extends PhoneBase { case EVENT_SET_VM_NUMBER_DONE: ar = (AsyncResult)msg.obj; - if (SimVmNotSupportedException.class.isInstance(ar.exception)) { + if (IccVmNotSupportedException.class.isInstance(ar.exception)) { storeVoiceMailNumber(mVmNumber); ar.exception = null; } @@ -1497,15 +1419,15 @@ public class GSMPhone extends PhoneBase { onComplete.sendToTarget(); } break; - + case EVENT_CALL_RING: ar = (AsyncResult)msg.obj; if (ar.exception == null) { notifyIncomingRing(); } break; - - // handle the select network completion callbacks. + + // handle the select network completion callbacks. case EVENT_SET_NETWORK_MANUAL_COMPLETE: case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: handleSetSelectNetwork((AsyncResult) msg.obj); @@ -1550,29 +1472,29 @@ public class GSMPhone extends PhoneBase { * Used to track the settings upon completion of the network change. */ private void handleSetSelectNetwork(AsyncResult ar) { - // look for our wrapper within the asyncresult, skip the rest if it - // is null. + // look for our wrapper within the asyncresult, skip the rest if it + // is null. if (!(ar.userObj instanceof NetworkSelectMessage)) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "unexpected result from user object."); return; } - + NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj; - + // found the object, now we send off the message we had originally - // attached to the request. + // attached to the request. if (nsm.message != null) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "sending original message to recipient"); AsyncResult.forMessage(nsm.message, ar.result, ar.exception); nsm.message.sendToTarget(); } - + // open the shared preferences editor, and write the value. // nsm.operatorNumeric is "" if we're in automatic.selection. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric); - + // commit and log the result. if (! editor.commit()) { Log.e(LOG_TAG, "failed to commit network selection preference"); @@ -1584,17 +1506,16 @@ public class GSMPhone extends PhoneBase { * Saves CLIR setting so that we can re-apply it as necessary * (in case the RIL resets it across reboots). */ - /* package */ void saveClirSetting(int commandInterfaceCLIRMode) { + public void saveClirSetting(int commandInterfaceCLIRMode) { // open the shared preferences editor, and write the value. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); editor.putInt(CLIR_KEY, commandInterfaceCLIRMode); - + // commit and log the result. if (! editor.commit()) { Log.e(LOG_TAG, "failed to commit CLIR preference"); } - } private void handleCfuQueryResult(CallForwardInfo[] infos) { @@ -1618,7 +1539,7 @@ public class GSMPhone extends PhoneBase { * simulates various data connection states. This messes with * DataConnectionTracker's internal states, but doesn't actually change * the underlying radio connection states. - * + * * @param state Phone.DataState enum. */ public void simulateDataConnection(Phone.DataState state) { @@ -1642,4 +1563,52 @@ public class GSMPhone extends PhoneBase { mDataConnection.setState(dcState); notifyDataConnection(null); } + + /** + * Retrieves the PhoneSubInfo of the GSMPhone + */ + public PhoneSubInfo getPhoneSubInfo(){ + return mSubInfo; + } + + /** + * Retrieves the IccSmsInterfaceManager of the GSMPhone + */ + public IccSmsInterfaceManager getIccSmsInterfaceManager(){ + return mSimSmsIntManager; + } + + /** + * Retrieves the IccPhoneBookInterfaceManager of the GSMPhone + */ + public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ + return mSimPhoneBookIntManager; + } + + /** + * {@inheritDoc} + */ + public Handler getHandler(){ + return h; + } + + /** + * {@inheritDoc} + */ + public IccFileHandler getIccFileHandler(){ + return this.mIccFileHandler; + } + + public void activateCellBroadcastSms(int activate, Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + + public void getCellBroadcastSmsConfig(Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java similarity index 75% rename from telephony/java/com/android/internal/telephony/gsm/GSMCall.java rename to telephony/java/com/android/internal/telephony/gsm/GsmCall.java index 4feaf21dd4b552b80bfdaf0b5f5dbc02b5573316..a92e52d0e1d52751de70852f0483adcf86739c43 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java @@ -15,26 +15,30 @@ */ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.Phone; + import java.util.ArrayList; import java.util.List; /** * {@hide} */ -class GSMCall extends Call -{ +class GsmCall extends Call { /*************************** Instance Variables **************************/ /*package*/ ArrayList connections = new ArrayList(); - /*package*/ State state = State.IDLE; - /*package*/ CallTracker owner; + /*package*/ GsmCallTracker owner; + /***************************** Class Methods *****************************/ static State - stateFromDCState (DriverCall.State dcState) - { + stateFromDCState (DriverCall.State dcState) { switch (dcState) { case ACTIVE: return State.ACTIVE; case HOLDING: return State.HOLDING; @@ -45,40 +49,33 @@ class GSMCall extends Call default: throw new RuntimeException ("illegal call state:" + dcState); } } - + /****************************** Constructors *****************************/ /*package*/ - GSMCall (CallTracker owner) - { + GsmCall (GsmCallTracker owner) { this.owner = owner; } + public void dispose() { + } + /************************** Overridden from Call *************************/ public List - getConnections() - { + getConnections() { // FIXME should return Collections.unmodifiableList(); return connections; } - public State - getState() - { - return state; - } - - public Phone - getPhone() - { + public Phone + getPhone() { //TODO return null; } public boolean - isMultiparty() - { + isMultiparty() { return connections.size() > 1; } @@ -86,66 +83,60 @@ class GSMCall extends Call * background call exists, the background call will be resumed * because an AT+CHLD=1 will be sent */ - public void - hangup() throws CallStateException - { + public void + hangup() throws CallStateException { owner.hangup(this); } public String - toString() - { + toString() { return state.toString(); } - //***** Called from GSMConnection + //***** Called from GsmConnection /*package*/ void - attach(GSMConnection conn, DriverCall dc) - { + attach(Connection conn, DriverCall dc) { connections.add(conn); state = stateFromDCState (dc.state); } /*package*/ void - attachFake(GSMConnection conn, State state) - { + attachFake(Connection conn, State state) { connections.add(conn); this.state = state; } /** - * Called by GSMConnection when it has disconnected + * Called by GsmConnection when it has disconnected */ void - connectionDisconnected(GSMConnection conn) - { + connectionDisconnected(GsmConnection conn) { if (state != State.DISCONNECTED) { /* If only disconnected connections remain, we are disconnected*/ boolean hasOnlyDisconnectedConnections = true; - + for (int i = 0, s = connections.size() ; i < s; i ++) { - if (connections.get(i).getState() + if (connections.get(i).getState() != State.DISCONNECTED ) { hasOnlyDisconnectedConnections = false; break; - } + } } if (hasOnlyDisconnectedConnections) { - state = State.DISCONNECTED; + state = State.DISCONNECTED; } - } + } } /*package*/ void - detach(GSMConnection conn) - { + detach(GsmConnection conn) { connections.remove(conn); if (connections.size() == 0) { @@ -154,13 +145,12 @@ class GSMCall extends Call } /*package*/ boolean - update (GSMConnection conn, DriverCall dc) - { + update (GsmConnection conn, DriverCall dc) { State newState; boolean changed = false; - + newState = stateFromDCState(dc.state); - + if (newState != state) { state = newState; changed = true; @@ -174,44 +164,41 @@ class GSMCall extends Call * connections to be added via "conference" */ /*package*/ boolean - isFull() - { - return connections.size() == CallTracker.MAX_CONNECTIONS_PER_CALL; + isFull() { + return connections.size() == GsmCallTracker.MAX_CONNECTIONS_PER_CALL; } - //***** Called from CallTracker + //***** Called from GsmCallTracker - /** + /** * Called when this Call is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio * but no response has yet been received so update() has not yet been called */ void - onHangupLocal() - { + onHangupLocal() { for (int i = 0, s = connections.size() ; i < s; i++ ) { - GSMConnection cn = (GSMConnection)connections.get(i); + GsmConnection cn = (GsmConnection)connections.get(i); cn.onHangupLocal(); } } - + /** * Called when it's time to clean up disconnected Connection objects */ void - clearDisconnected() - { + clearDisconnected() { for (int i = connections.size() - 1 ; i >= 0 ; i--) { - GSMConnection cn = (GSMConnection)connections.get(i); - + GsmConnection cn = (GsmConnection)connections.get(i); + if (cn.getState() == State.DISCONNECTED) { connections.remove(i); } - } + } if (connections.size() == 0) { state = State.IDLE; diff --git a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java similarity index 79% rename from telephony/java/com/android/internal/telephony/gsm/CallTracker.java rename to telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java index 2d716bb54b538b5929990b86fab0ae111ae702fa..5c5090ffe9116543f57971cfcccc1611443e50a5 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java @@ -16,37 +16,34 @@ 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.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.Registrant; -import android.os.RegistrantList; -import android.os.SystemProperties; +import android.os.*; +import android.telephony.gsm.GsmCellLocation; 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.CallTracker; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.gsm.CallFailCause; +import com.android.internal.telephony.gsm.GsmCall; +import com.android.internal.telephony.gsm.GsmConnection; +import com.android.internal.telephony.gsm.GSMPhone; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyEventLog; +import com.android.internal.telephony.*; -import java.util.ArrayList; import java.util.List; +import java.util.ArrayList; /** * {@hide} */ -public final class CallTracker extends Handler -{ +public final class GsmCallTracker extends CallTracker { static final String LOG_TAG = "GSM"; private static final boolean REPEAT_POLLING = false; @@ -54,59 +51,41 @@ public final class CallTracker extends Handler //***** Constants - static final int POLL_DELAY_MSEC = 250; static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call //***** Instance Variables - - GSMConnection connections[] = new GSMConnection[MAX_CONNECTIONS]; + GsmConnection connections[] = new GsmConnection[MAX_CONNECTIONS]; RegistrantList voiceCallEndedRegistrants = new RegistrantList(); RegistrantList voiceCallStartedRegistrants = new RegistrantList(); // connections dropped durin last poll - ArrayList droppedDuringPoll - = new ArrayList(MAX_CONNECTIONS); + ArrayList droppedDuringPoll + = new ArrayList(MAX_CONNECTIONS); - GSMCall ringingCall = new GSMCall(this); + GsmCall ringingCall = new GsmCall(this); // A call that is ringing or (call) waiting - GSMCall foregroundCall = new GSMCall(this); - GSMCall backgroundCall = new GSMCall(this); + GsmCall foregroundCall = new GsmCall(this); + GsmCall backgroundCall = new GsmCall(this); - GSMConnection pendingMO; + GsmConnection pendingMO; boolean hangupPendingMO; GSMPhone phone; - CommandsInterface cm; + boolean desiredMute = false; // false = mute off Phone.State state = Phone.State.IDLE; - int pendingOperations; - boolean needsPoll; - Message lastRelevantPoll; //***** Events - static final int EVENT_POLL_CALLS_RESULT = 1; - static final int EVENT_CALL_STATE_CHANGE = 2; - static final int EVENT_REPOLL_AFTER_DELAY = 3; - static final int EVENT_OPERATION_COMPLETE = 4; - static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5; - - static final int EVENT_SWITCH_RESULT = 8; - static final int EVENT_RADIO_AVAILABLE = 9; - static final int EVENT_RADIO_NOT_AVAILABLE = 10; - static final int EVENT_CONFERENCE_RESULT = 11; - static final int EVENT_SEPARATE_RESULT = 12; - static final int EVENT_ECT_RESULT = 13; //***** Constructors - CallTracker (GSMPhone phone) - { + GsmCallTracker (GSMPhone phone) { this.phone = phone; cm = phone.mCM; @@ -116,24 +95,56 @@ public final class CallTracker extends Handler cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); } + public void dispose() { + //Unregister for all events + cm.unregisterForCallStateChanged(this); + cm.unregisterForOn(this); + cm.unregisterForNotAvailable(this); + + for(GsmConnection c : connections) { + try { + if(c != null) hangup(c); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + } + + try { + if(pendingMO != null) hangup(pendingMO); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + + clearDisconnected(); + } + + protected void finalize() { + Log.d(LOG_TAG, "GsmCallTracker finalized"); + } + //***** Instance Methods //***** Public Methods - public void registerForVoiceCallStarted(Handler h, int what, Object obj) - { + public void registerForVoiceCallStarted(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); voiceCallStartedRegistrants.add(r); } - public void registerForVoiceCallEnded(Handler h, int what, Object obj) - { + public void unregisterForVoiceCallStarted(Handler h) { + voiceCallStartedRegistrants.remove(h); + } + + public void registerForVoiceCallEnded(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); voiceCallEndedRegistrants.add(r); } + public void unregisterForVoiceCallEnded(Handler h) { + voiceCallEndedRegistrants.remove(h); + } + private void - fakeHoldForegroundBeforeDial() - { + fakeHoldForegroundBeforeDial() { List connCopy; // We need to make a copy here, since fakeHoldBeforeDial() @@ -141,7 +152,7 @@ public final class CallTracker extends Handler connCopy = (List) foregroundCall.connections.clone(); for (int i = 0, s = connCopy.size() ; i < s ; i++) { - GSMConnection conn = (GSMConnection)connCopy.get(i); + GsmConnection conn = (GsmConnection)connCopy.get(i); conn.fakeHoldBeforeDial(); } @@ -162,7 +173,7 @@ public final class CallTracker extends Handler // The new call must be assigned to the foreground call. // That call must be idle, so place anything that's // there on hold - if (foregroundCall.getState() == Call.State.ACTIVE) { + if (foregroundCall.getState() == GsmCall.State.ACTIVE) { // this will probably be done by the radio anyway // but the dial might fail before this happens // and we need to make sure the foreground call is clear @@ -176,12 +187,12 @@ public final class CallTracker extends Handler fakeHoldForegroundBeforeDial(); } - if (foregroundCall.getState() != Call.State.IDLE) { + if (foregroundCall.getState() != GsmCall.State.IDLE) { //we should have failed in !canDial() above before we get here throw new CallStateException("cannot dial in current state"); } - pendingMO = new GSMConnection(phone.getContext(), dialString, this, foregroundCall); + pendingMO = new GsmConnection(phone.getContext(), dialString, this, foregroundCall); hangupPendingMO = false; if (pendingMO.address == null || pendingMO.address.length() == 0 @@ -208,24 +219,22 @@ public final class CallTracker extends Handler Connection - dial (String dialString) throws CallStateException - { + dial (String dialString) throws CallStateException { return dial(dialString, CommandsInterface.CLIR_DEFAULT); } void - acceptCall () throws CallStateException - { + acceptCall () throws CallStateException { // FIXME if SWITCH fails, should retry with ANSWER // in case the active/holding call disappeared and this // is no longer call waiting - if (ringingCall.getState() == Call.State.INCOMING) { + if (ringingCall.getState() == GsmCall.State.INCOMING) { Log.i("phone", "acceptCall: incoming..."); // Always unmute when answering a new call setMute(false); cm.acceptCall(obtainCompleteMessage()); - } else if (ringingCall.getState() == Call.State.WAITING) { + } else if (ringingCall.getState() == GsmCall.State.WAITING) { setMute(false); switchWaitingOrHoldingAndActive(); } else { @@ -234,8 +243,7 @@ public final class CallTracker extends Handler } void - rejectCall () throws CallStateException - { + rejectCall () throws CallStateException { // AT+CHLD=0 means "release held or UDUB" // so if the phone isn't ringing, this could hang up held if (ringingCall.getState().isRinging()) { @@ -248,7 +256,7 @@ public final class CallTracker extends Handler void switchWaitingOrHoldingAndActive() throws CallStateException { // Should we bother with this check? - if (ringingCall.getState() == Call.State.INCOMING) { + if (ringingCall.getState() == GsmCall.State.INCOMING) { throw new CallStateException("cannot be in the incoming state"); } else { cm.switchWaitingOrHoldingAndActive( @@ -257,20 +265,17 @@ public final class CallTracker extends Handler } void - conference() throws CallStateException - { + conference() throws CallStateException { cm.conference(obtainCompleteMessage(EVENT_CONFERENCE_RESULT)); } void - explicitCallTransfer() throws CallStateException - { + explicitCallTransfer() throws CallStateException { cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT)); } void - clearDisconnected() - { + clearDisconnected() { internalClearDisconnected(); updatePhoneState(); @@ -278,17 +283,15 @@ public final class CallTracker extends Handler } boolean - canConference() - { - return foregroundCall.getState() == Call.State.ACTIVE - && backgroundCall.getState() == Call.State.HOLDING + canConference() { + return foregroundCall.getState() == GsmCall.State.ACTIVE + && backgroundCall.getState() == GsmCall.State.HOLDING && !backgroundCall.isFull() && !foregroundCall.isFull(); } boolean - canDial() - { + canDial() { boolean ret; int serviceState = phone.getServiceState().getState(); @@ -302,42 +305,26 @@ public final class CallTracker extends Handler } boolean - canTransfer() - { - return foregroundCall.getState() == Call.State.ACTIVE - && backgroundCall.getState() == Call.State.HOLDING; + canTransfer() { + return foregroundCall.getState() == GsmCall.State.ACTIVE + && backgroundCall.getState() == GsmCall.State.HOLDING; } //***** Private Instance Methods private void - internalClearDisconnected() - { + internalClearDisconnected() { ringingCall.clearDisconnected(); foregroundCall.clearDisconnected(); backgroundCall.clearDisconnected(); } - /** - * @return true if we're idle or there's a call to getCurrentCalls() pending - * but nothing else - */ - private boolean - checkNoOperationsPending() - { - if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" + - pendingOperations); - return pendingOperations == 0; - } - - /** * Obtain a message to use for signalling "invoke getCurrentCalls() when * this operation and all other pending operations are complete */ private Message - obtainCompleteMessage() - { + obtainCompleteMessage() { return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); } @@ -346,8 +333,7 @@ public final class CallTracker extends Handler * this operation and all other pending operations are complete */ private Message - obtainCompleteMessage(int what) - { + obtainCompleteMessage(int what) { pendingOperations++; lastRelevantPoll = null; needsPoll = true; @@ -358,26 +344,8 @@ public final class CallTracker extends Handler return obtainMessage(what); } - /** - * Obtain a complete message that indicates that this operation - * does not require polling of getCurrentCalls(). However, if other - * operations that do need getCurrentCalls() are pending or are - * scheduled while this operation is pending, the invocatoin - * of getCurrentCalls() will be postponed until this - * operation is also complete. - */ - private Message - obtainNoPollCompleteMessage(int what) - { - pendingOperations++; - lastRelevantPoll = null; - return obtainMessage(what); - } - - private void - operationComplete() - { + operationComplete() { pendingOperations--; if (DBG_POLL) log("operationComplete: pendingOperations=" + @@ -388,42 +356,13 @@ public final class CallTracker extends Handler cm.getCurrentCalls(lastRelevantPoll); } else if (pendingOperations < 0) { // this should never happen - Log.e(LOG_TAG,"CallTracker.pendingOperations < 0"); + Log.e(LOG_TAG,"GsmCallTracker.pendingOperations < 0"); pendingOperations = 0; } } private void - pollCallsWhenSafe() - { - needsPoll = true; - - if (checkNoOperationsPending()) { - lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); - cm.getCurrentCalls(lastRelevantPoll); - } - } - - private void - pollCallsAfterDelay() - { - Message msg = obtainMessage(); - - msg.what = EVENT_REPOLL_AFTER_DELAY; - sendMessageDelayed(msg, POLL_DELAY_MSEC); - } - - private boolean - isCommandExceptionRadioNotAvailable(Throwable e) - { - return e != null && e instanceof CommandException - && ((CommandException)e).getCommandError() - == CommandException.Error.RADIO_NOT_AVAILABLE; - } - - private void - updatePhoneState() - { + updatePhoneState() { Phone.State oldState = state; if (ringingCall.isRinging()) { @@ -448,9 +387,8 @@ public final class CallTracker extends Handler } } - private void - handlePollCalls(AsyncResult ar) - { + protected void + handlePollCalls(AsyncResult ar) { List polledCalls; if (ar.exception == null) { @@ -474,7 +412,7 @@ public final class CallTracker extends Handler for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < connections.length; i++) { - GSMConnection conn = connections[i]; + GsmConnection conn = connections[i]; DriverCall dc = null; // polledCall list is sparse @@ -519,7 +457,7 @@ public final class CallTracker extends Handler return; } } else { - connections[i] = new GSMConnection(phone.getContext(), dc, this, i); + connections[i] = new GsmConnection(phone.getContext(), dc, this, i); // it's a ringing call if (connections[i].getCall() == ringingCall) { @@ -549,14 +487,14 @@ public final class CallTracker extends Handler // tracking. droppedDuringPoll.add(conn); // Dropped connections are removed from the CallTracker - // list but kept in the GSMCall list + // list but kept in the GsmCall list connections[i] = null; } else if (conn != null && dc != null && !conn.compareTo(dc)) { // Connection in CLCC response does not match what // we were tracking. Assume dropped call and new call droppedDuringPoll.add(conn); - connections[i] = new GSMConnection (phone.getContext(), dc, this, i); + connections[i] = new GsmConnection (phone.getContext(), dc, this, i); if (connections[i].getCall() == ringingCall) { newRinging = connections[i]; @@ -608,7 +546,7 @@ public final class CallTracker extends Handler // cases from the "dropped during poll" list // These cases need no "last call fail" reason for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) { - GSMConnection conn = droppedDuringPoll.get(i); + GsmConnection conn = droppedDuringPoll.get(i); if (conn.isIncoming() && conn.getConnectTime() == 0) { // Missed or rejected call @@ -630,7 +568,7 @@ public final class CallTracker extends Handler droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.LOCAL); } else if (conn.cause == - Connection.DisconnectCause.INVALID_NUMBER) { + Connection.DisconnectCause.INVALID_NUMBER) { droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER); } @@ -669,14 +607,7 @@ public final class CallTracker extends Handler } private void - handleRadioAvailable() - { - pollCallsWhenSafe(); - } - - private void - handleRadioNotAvailable() - { + handleRadioNotAvailable() { // handlePollCalls will clear out its // call list when it gets the CommandException // error result from this @@ -684,8 +615,7 @@ public final class CallTracker extends Handler } private void - dumpState() - { + dumpState() { List l; Log.i(LOG_TAG,"Phone State:" + state); @@ -713,14 +643,13 @@ public final class CallTracker extends Handler } - //***** Called from GSMConnection + //***** Called from GsmConnection /*package*/ void - hangup (GSMConnection conn) throws CallStateException - { + hangup (GsmConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("Connection " + conn - + "does not belong to CallTracker " + this); + throw new CallStateException ("GsmConnection " + conn + + "does not belong to GsmCallTracker " + this); } if (conn == pendingMO) { @@ -735,7 +664,7 @@ public final class CallTracker extends Handler } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"CallTracker WARN: hangup() on absent connection " + Log.w(LOG_TAG,"GsmCallTracker WARN: hangup() on absent connection " + conn); } } @@ -744,11 +673,10 @@ public final class CallTracker extends Handler } /*package*/ void - separate (GSMConnection conn) throws CallStateException - { + separate (GsmConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("Connection " + conn - + "does not belong to CallTracker " + this); + throw new CallStateException ("GsmConnection " + conn + + "does not belong to GsmCallTracker " + this); } try { cm.separateConnection (conn.getGSMIndex(), @@ -756,7 +684,7 @@ public final class CallTracker extends Handler } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"CallTracker WARN: separate() on absent connection " + Log.w(LOG_TAG,"GsmCallTracker WARN: separate() on absent connection " + conn); } } @@ -764,24 +692,21 @@ public final class CallTracker extends Handler //***** Called from GSMPhone /*package*/ void - setMute(boolean mute) - { + setMute(boolean mute) { desiredMute = mute; cm.setMute(desiredMute, null); } /*package*/ boolean - getMute() - { + getMute() { return desiredMute; } - //***** Called from GSMCall + //***** Called from GsmCall /* package */ void - hangup (GSMCall call) throws CallStateException - { + hangup (GsmCall call) throws CallStateException { if (call.getConnections().size() == 0) { throw new CallStateException("no connections in call"); } @@ -794,7 +719,7 @@ public final class CallTracker extends Handler if (Phone.DEBUG_PHONE) { log("(foregnd) hangup dialing or alerting..."); } - hangup((GSMConnection)(call.getConnections().get(0))); + hangup((GsmConnection)(call.getConnections().get(0))); } else { hangupForegroundResumeBackground(); } @@ -808,8 +733,8 @@ public final class CallTracker extends Handler hangupWaitingOrBackground(); } } else { - throw new RuntimeException ("Call " + call + - "does not belong to CallTracker " + this); + throw new RuntimeException ("GsmCall " + call + + "does not belong to GsmCallTracker " + this); } call.onHangupLocal(); @@ -827,11 +752,11 @@ public final class CallTracker extends Handler cm.hangupForegroundResumeBackground(obtainCompleteMessage()); } - void hangupConnectionByIndex(GSMCall call, int index) + void hangupConnectionByIndex(GsmCall call, int index) throws CallStateException { int count = call.connections.size(); for (int i = 0; i < count; i++) { - GSMConnection cn = (GSMConnection)call.connections.get(i); + GsmConnection cn = (GsmConnection)call.connections.get(i); if (cn.getGSMIndex() == index) { cm.hangupConnection(index, obtainCompleteMessage()); return; @@ -841,11 +766,11 @@ public final class CallTracker extends Handler throw new CallStateException("no gsm index found"); } - void hangupAllConnections(GSMCall call) throws CallStateException{ + void hangupAllConnections(GsmCall call) throws CallStateException{ try { int count = call.connections.size(); for (int i = 0; i < count; i++) { - GSMConnection cn = (GSMConnection)call.connections.get(i); + GsmConnection cn = (GsmConnection)call.connections.get(i); cm.hangupConnection(cn.getGSMIndex(), obtainCompleteMessage()); } } catch (CallStateException ex) { @@ -854,11 +779,11 @@ public final class CallTracker extends Handler } /* package */ - GSMConnection getConnectionByIndex(GSMCall call, int index) + GsmConnection getConnectionByIndex(GsmCall call, int index) throws CallStateException { int count = call.connections.size(); for (int i = 0; i < count; i++) { - GSMConnection cn = (GSMConnection)call.connections.get(i); + GsmConnection cn = (GsmConnection)call.connections.get(i); if (cn.getGSMIndex() == index) { return cn; } @@ -884,8 +809,7 @@ public final class CallTracker extends Handler //****** Overridden from Handler public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { @@ -952,7 +876,7 @@ public final class CallTracker extends Handler for (int i = 0, s = droppedDuringPoll.size() ; i < s ; i++ ) { - GSMConnection conn = droppedDuringPoll.get(i); + GsmConnection conn = droppedDuringPoll.get(i); conn.onRemoteDisconnect(causeCode); } @@ -978,7 +902,7 @@ public final class CallTracker extends Handler } } - private void log(String msg) { - Log.d(LOG_TAG, "[CallTracker] " + msg); + protected void log(String msg) { + Log.d(LOG_TAG, "[GsmCallTracker] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java similarity index 85% rename from telephony/java/com/android/internal/telephony/gsm/GSMConnection.java rename to telephony/java/com/android/internal/telephony/gsm/GsmConnection.java index 477789244f1fe91c72dc44a66ddd1f4f62cceae4..2b2f077fd8943176c665c7688dc761a4e74d2611 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java @@ -15,39 +15,39 @@ */ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; - import android.content.Context; +import android.os.AsyncResult; import android.os.Handler; -import android.os.PowerManager; -import android.os.Registrant; import android.os.Looper; import android.os.Message; -import android.os.AsyncResult; +import android.os.PowerManager; +import android.os.Registrant; import android.os.SystemClock; -import android.util.Log; import android.util.Config; +import android.util.Log; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import com.android.internal.telephony.*; + /** * {@hide} */ -public class GSMConnection extends Connection { +public class GsmConnection extends Connection { static final String LOG_TAG = "GSM"; //***** Instance Variables - CallTracker owner; - GSMCall parent; + GsmCallTracker owner; + GsmCall parent; String address; // MAY BE NULL!!! String dialString; // outgoing calls only - String postDialString; // outgoing calls only + String postDialString; // outgoing calls only boolean isIncoming; - boolean disconnected; + boolean disconnected; - int index; // index in CallTracker.connections[], -1 if unassigned + int index; // index in GsmCallTracker.connections[], -1 if unassigned // The GSM index is 1 + this /* @@ -65,7 +65,7 @@ public class GSMConnection extends Connection { */ long connectTimeReal; long duration; - long holdingStartTime; // The time when the Connection last transitioned + long holdingStartTime; // The time when the Connection last transitioned // into HOLDING int nextPostDialChar; // index into postDialString @@ -95,8 +95,8 @@ public class GSMConnection extends Connection { MyHandler(Looper l) {super(l);} public void - handleMessage(Message msg) - { + handleMessage(Message msg) { + switch (msg.what) { case EVENT_NEXT_POST_DIAL: case EVENT_DTMF_DONE: @@ -114,11 +114,10 @@ public class GSMConnection extends Connection { /** This is probably an MT call that we first saw in a CLCC response */ /*package*/ - GSMConnection (Context context, DriverCall dc, CallTracker ct, int index) - { + GsmConnection (Context context, DriverCall dc, GsmCallTracker ct, int index) { createWakeLock(context); acquireWakeLock(); - + owner = ct; h = new MyHandler(owner.getLooper()); @@ -136,11 +135,10 @@ public class GSMConnection extends Connection { /** This is an MO call, created when dialing */ /*package*/ - GSMConnection (Context context, String dialString, CallTracker ct, GSMCall parent) - { + GsmConnection (Context context, String dialString, GsmCallTracker ct, GsmCall parent) { createWakeLock(context); acquireWakeLock(); - + owner = ct; h = new MyHandler(owner.getLooper()); @@ -155,18 +153,19 @@ public class GSMConnection extends Connection { createTime = System.currentTimeMillis(); this.parent = parent; - parent.attachFake(this, Call.State.DIALING); + parent.attachFake(this, GsmCall.State.DIALING); } - + + public void dispose() { + } + static boolean - equalsHandlesNulls (Object a, Object b) - { + equalsHandlesNulls (Object a, Object b) { return (a == null) ? (b == null) : a.equals (b); } /*package*/ boolean - compareTo(DriverCall c) - { + compareTo(DriverCall c) { // On mobile originated (MO) calls, the phone number may have changed // due to a SIM Toolkit call control modification. // @@ -178,43 +177,35 @@ public class GSMConnection extends Connection { // no control over when they begin, so we might as well String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); - return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); + return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); } public String - toString() - { + toString() { return (isIncoming ? "incoming" : "outgoing"); } - public String getAddress() - { - return address; + public String getAddress() { + return address; } - - public Call getCall() - { + public GsmCall getCall() { return parent; } - public long getCreateTime() - { + public long getCreateTime() { return createTime; } - public long getConnectTime() - { + public long getConnectTime() { return connectTime; } - public long getDisconnectTime() - { + public long getDisconnectTime() { return disconnectTime; } - public long getDurationMillis() - { + public long getDurationMillis() { if (connectTimeReal == 0) { return 0; } else if (duration == 0) { @@ -224,9 +215,8 @@ public class GSMConnection extends Connection { } } - public long getHoldDurationMillis() - { - if (getState() != Call.State.HOLDING) { + public long getHoldDurationMillis() { + if (getState() != GsmCall.State.HOLDING) { // If not holding, return 0 return 0; } else { @@ -234,52 +224,45 @@ public class GSMConnection extends Connection { } } - public DisconnectCause getDisconnectCause() - { + public DisconnectCause getDisconnectCause() { return cause; } - public boolean isIncoming() - { + public boolean isIncoming() { return isIncoming; } - public Call.State getState() - { + public GsmCall.State getState() { if (disconnected) { - return Call.State.DISCONNECTED; - } else { + return GsmCall.State.DISCONNECTED; + } else { return super.getState(); } } - public void hangup() throws CallStateException - { - if (!disconnected) { + public void hangup() throws CallStateException { + if (!disconnected) { owner.hangup(this); } else { throw new CallStateException ("disconnected"); } } - public void separate() throws CallStateException - { - if (!disconnected) { + public void separate() throws CallStateException { + if (!disconnected) { owner.separate(this); } else { throw new CallStateException ("disconnected"); } } - public PostDialState getPostDialState() - { + public PostDialState getPostDialState() { return postDialState; } - public void proceedAfterWaitChar() - { + public void proceedAfterWaitChar() { if (postDialState != PostDialState.WAIT) { - Log.w(LOG_TAG, "Connection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WAIT but was " + postDialState); return; } @@ -288,10 +271,10 @@ public class GSMConnection extends Connection { processNextPostDialChar(); } - + public void proceedAfterWildChar(String str) { if (postDialState != PostDialState.WILD) { - Log.w(LOG_TAG, "Connection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WILD but was " + postDialState); return; } @@ -328,38 +311,35 @@ public class GSMConnection extends Connection { postDialString = buf.toString(); nextPostDialChar = 0; if (Phone.DEBUG_PHONE) { - log("proceedAfterWildChar: new postDialString is " + + log("proceedAfterWildChar: new postDialString is " + postDialString); } processNextPostDialChar(); } } - - public void cancelPostDial() - { + + public void cancelPostDial() { setPostDialState(PostDialState.CANCELLED); } - /** + /** * Called when this Connection is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio - * but no response has yet been received so update() has not yet been called + * but no response has yet been received so update() has not yet been called */ void - onHangupLocal() - { + onHangupLocal() { cause = DisconnectCause.LOCAL; } DisconnectCause - disconnectCauseFromCode(int causeCode) - { + disconnectCauseFromCode(int causeCode) { /** * See 22.001 Annex F.4 for mapping of cause codes * to local tones */ - + switch (causeCode) { case CallFailCause.USER_BUSY: return DisconnectCause.BUSY; @@ -382,7 +362,7 @@ public class GSMConnection extends Connection { return DisconnectCause.FDN_BLOCKED; case CallFailCause.ERROR_UNSPECIFIED: - case CallFailCause.NORMAL_CLEARING: + case CallFailCause.NORMAL_CLEARING: default: GSMPhone phone = owner.phone; int serviceState = phone.getServiceState().getState(); @@ -391,8 +371,8 @@ public class GSMConnection extends Connection { } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) { return DisconnectCause.OUT_OF_SERVICE; - } else if (phone.getSimCard().getState() != GsmSimCard.State.READY) { - return DisconnectCause.SIM_ERROR; + } else if (phone.getIccCard().getState() != SimCard.State.READY) { + return DisconnectCause.ICC_ERROR; } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) { if (phone.mSST.rs.isCsRestricted()) { return DisconnectCause.CS_RESTRICTED; @@ -410,20 +390,18 @@ public class GSMConnection extends Connection { } /*package*/ void - onRemoteDisconnect(int causeCode) - { + onRemoteDisconnect(int causeCode) { onDisconnect(disconnectCauseFromCode(causeCode)); } /** Called when the radio indicates the connection has been disconnected */ /*package*/ void - onDisconnect(DisconnectCause cause) - { + onDisconnect(DisconnectCause cause) { this.cause = cause; - - if (!disconnected) { + + if (!disconnected) { index = -1; - + disconnectTime = System.currentTimeMillis(); duration = SystemClock.elapsedRealtime() - connectTimeReal; disconnected = true; @@ -434,7 +412,7 @@ public class GSMConnection extends Connection { owner.phone.notifyDisconnect(this); if (parent != null) { - parent.connectionDisconnected(this); + parent.connectionDisconnected(this); } } releaseWakeLock(); @@ -443,10 +421,10 @@ public class GSMConnection extends Connection { // Returns true if state has changed, false if nothing changed /*package*/ boolean update (DriverCall dc) { - GSMCall newParent; + GsmCall newParent; boolean changed = false; boolean wasConnectingInOrOut = isConnectingInOrOut(); - boolean wasHolding = (getState() == Call.State.HOLDING); + boolean wasHolding = (getState() == GsmCall.State.HOLDING); newParent = parentFromDCState(dc.state); @@ -484,7 +462,7 @@ public class GSMConnection extends Connection { onConnectedInOrOut(); } - if (changed && !wasHolding && (getState() == Call.State.HOLDING)) { + if (changed && !wasHolding && (getState() == GsmCall.State.HOLDING)) { // We've transitioned into HOLDING onStartedHolding(); } @@ -499,14 +477,13 @@ public class GSMConnection extends Connection { * HOLDING in the backgroundCall */ void - fakeHoldBeforeDial() - { + fakeHoldBeforeDial() { if (parent != null) { parent.detach(this); } parent = owner.backgroundCall; - parent.attachFake(this, Call.State.HOLDING); + parent.attachFake(this, GsmCall.State.HOLDING); onStartedHolding(); } @@ -552,28 +529,27 @@ public class GSMConnection extends Connection { * should be ignored */ private boolean - processPostDialChar(char c) - { + processPostDialChar(char c) { if (PhoneNumberUtils.is12Key(c)) { owner.cm.sendDtmf(c, h.obtainMessage(EVENT_DTMF_DONE)); } else if (c == PhoneNumberUtils.PAUSE) { // From TS 22.101: - // "The first occurrence of the "DTMF Control Digits Separator" - // shall be used by the ME to distinguish between the addressing + // "The first occurrence of the "DTMF Control Digits Separator" + // shall be used by the ME to distinguish between the addressing // digits (i.e. the phone number) and the DTMF digits...." if (nextPostDialChar == 1) { // The first occurrence. // We don't need to pause here, but wait for just a bit anyway - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_FIRST_MILLIS); } else { // It continues... - // "Upon subsequent occurrences of the separator, the UE shall - // pause again for 3 seconds (\u00B1 20 %) before sending any + // "Upon subsequent occurrences of the separator, the UE shall + // pause again for 3 seconds (\u00B1 20 %) before sending any // further DTMF digits." - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_MILLIS); } } else if (c == PhoneNumberUtils.WAIT) { @@ -588,9 +564,8 @@ public class GSMConnection extends Connection { } public String - getRemainingPostDialString() - { - if (postDialState == PostDialState.CANCELLED + getRemainingPostDialString() { + if (postDialState == PostDialState.CANCELLED || postDialState == PostDialState.COMPLETE || postDialString == null || postDialString.length() <= nextPostDialChar @@ -617,8 +592,7 @@ public class GSMConnection extends Connection { } private void - processNextPostDialChar() - { + processNextPostDialChar() { char c = 0; Registrant postDialHandler; @@ -655,7 +629,8 @@ public class GSMConnection extends Connection { Message notifyMessage; - if (postDialHandler != null && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { + if (postDialHandler != null + && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { // The AsyncResult.result is the Connection object PostDialState state = postDialState; AsyncResult ar = AsyncResult.forMessage(notifyMessage); @@ -668,14 +643,6 @@ public class GSMConnection extends Connection { //Log.v("GSM", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c); notifyMessage.sendToTarget(); } - /* - else { - if (postDialHandler == null) - Log.v("GSM", "##### processNextPostDialChar: postDialHandler is NULL!"); - else - Log.v("GSM", "##### processNextPostDialChar: postDialHandler.messageForRegistrant() returned NULL!"); - } - */ } @@ -683,16 +650,14 @@ public class GSMConnection extends Connection { * and outgoing calls */ private boolean - isConnectingInOrOut() - { - return parent == null || parent == owner.ringingCall - || parent.state == Call.State.DIALING - || parent.state == Call.State.ALERTING; + isConnectingInOrOut() { + return parent == null || parent == owner.ringingCall + || parent.state == GsmCall.State.DIALING + || parent.state == GsmCall.State.ALERTING; } - private GSMCall - parentFromDCState (DriverCall.State state) - { + private GsmCall + parentFromDCState (DriverCall.State state) { switch (state) { case ACTIVE: case DIALING: diff --git a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java similarity index 68% rename from telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java rename to telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 02a684146adbc6a63ab36e1c1567de41411f43e2..9e6ebc4255ee02b298546b23d89b48b12073e520 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -50,8 +50,12 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataConnection.FailCause; +import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.PdpConnection.PdpFailCause; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.TelephonyEventLog; import java.io.IOException; import java.util.ArrayList; @@ -59,44 +63,10 @@ import java.util.ArrayList; /** * {@hide} */ -final class DataConnectionTracker extends Handler -{ +public final class GsmDataConnectionTracker extends DataConnectionTracker { private static final String LOG_TAG = "GSM"; private static final boolean DBG = true; - /** - * IDLE: ready to start data connection setup, default state - * INITING: state of issued setupDefaultPDP() but not finish yet - * CONNECTING: state of issued startPppd() but not finish yet - * 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 or DISCONNECTING - */ - enum State { - IDLE, - INITING, - CONNECTING, - SCANNING, - CONNECTED, - DISCONNECTING, - FAILED - } - - enum Activity { - NONE, - DATAIN, - DATAOUT, - DATAINANDOUT - } - /** * Handles changes to the APN db. */ @@ -113,20 +83,12 @@ final class DataConnectionTracker extends Handler //***** Instance Variables - GSMPhone phone; INetStatService netstat; - State state = State.IDLE; - Activity activity = Activity.NONE; - boolean netStatPollEnabled = false; // Indicates baseband will not auto-attach private boolean noAutoAttach = false; long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - Handler mDataConnectionTracker = null; private ContentResolver mResolver; - long txPkts, rxPkts, sentSinceLastRecv; - int netStatPollPeriod; - private int mNoRecvPollCount = 0; private boolean mPingTestActive = false; // Count of PDP reset attempts; reset when we see incoming, // call reRegisterNetwork, or pingTest succeeds. @@ -156,10 +118,7 @@ final class DataConnectionTracker extends Handler /** * pdpList holds all the PDP connection, i.e. IP Link in GPRS */ - private ArrayList pdpList; - - /** CID of active PDP */ - int cidActive; + private ArrayList pdpList; /** Currently requested APN type */ private String mRequestedApnType = Phone.APN_TYPE_DEFAULT; @@ -172,16 +131,11 @@ final class DataConnectionTracker extends Handler private static int APN_DEFAULT_ID = 0; private static int APN_MMS_ID = 1; - private static int APN_NUM_TYPES = 2; + private static int APN_SUPL_ID = 2; + private static int APN_NUM_TYPES = 3; 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; - /** Is packet service restricted by network */ private boolean mIsPsRestricted = false; @@ -195,70 +149,11 @@ final class DataConnectionTracker extends Handler private static final int PDP_CONNECTION_POOL_SIZE = 1; 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; - - /** Default ping deadline, in seconds. */ - private static final int DEFAULT_PING_DEADLINE = 5; - /** Default max failure count before attempting to network re-registration. */ - private static final int DEFAULT_MAX_PDP_RESET_FAIL = 3; - - /** - * After detecting a potential connection problem, this is the max number - * of subsequent polls before attempting a radio reset. At this point, - * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to - * poll for about 2 more minutes. - */ - private static final int NO_RECV_POLL_LIMIT = 24; - - // 1 sec. default polling interval when screen is on. - private static final int POLL_NETSTAT_MILLIS = 1000; - // 10 min. default polling interval when screen is off. - private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; - // 2 min for round trip time - private static final int POLL_LONGEST_RTT = 120 * 1000; - // 10 for packets without ack - private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; - // how long to wait before switching back to default APN - private static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; - // system property that can override the above value - private static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; - // represents an invalid IP address - private static final String NULL_IP = "0.0.0.0"; + //WINK:TODO: Teleca, is this really gsm specific, what about CDMA? private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; - - //***** Event Codes - static final int EVENT_DATA_SETUP_COMPLETE = 1; - static final int EVENT_RADIO_AVAILABLE = 3; - static final int EVENT_RECORDS_LOADED = 4; - static final int EVENT_TRY_SETUP_DATA = 5; - static final int EVENT_PDP_STATE_CHANGED = 6; - static final int EVENT_POLL_PDP = 7; - static final int EVENT_GET_PDP_LIST_COMPLETE = 11; - static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12; - static final int EVENT_VOICE_CALL_STARTED = 14; - static final int EVENT_VOICE_CALL_ENDED = 15; - static final int EVENT_GPRS_DETACHED = 19; - static final int EVENT_LINK_STATE_CHANGED = 20; - static final int EVENT_ROAMING_ON = 21; - static final int EVENT_ROAMING_OFF = 22; - static final int EVENT_ENABLE_NEW_APN = 23; - static final int EVENT_RESTORE_DEFAULT_APN = 24; - static final int EVENT_DISCONNECT_DONE = 25; - 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; - static final int EVENT_PS_RESTRICT_ENABLED = 30; - static final int EVENT_PS_RESTRICT_DISABLED = 31; - static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn"); static final String APN_ID = "apn_id"; private boolean canSetPreferApn = false; @@ -307,21 +202,21 @@ final class DataConnectionTracker extends Handler //***** Constructor - DataConnectionTracker(GSMPhone phone) - { - this.phone = phone; - phone.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); - phone.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - phone.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); - phone.mCM.registerForPDPStateChanged (this, EVENT_PDP_STATE_CHANGED, null); - phone.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); - phone.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); - phone.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null); - phone.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null); - phone.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); - phone.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); - phone.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); - phone.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); + GsmDataConnectionTracker(GSMPhone p) { + super(p); + + p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); + p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null); + p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); + p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); + p.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null); + p.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null); + p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); + p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); + p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); @@ -332,14 +227,14 @@ final class DataConnectionTracker extends Handler filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - phone.getContext().registerReceiver(mIntentReceiver, filter, null, phone.h); + p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h); mDataConnectionTracker = this; mResolver = phone.getContext().getContentResolver(); apnObserver = new ApnChangeObserver(); - phone.getContext().getContentResolver().registerContentObserver( + p.getContext().getContentResolver().registerContentObserver( Telephony.Carriers.CONTENT_URI, true, apnObserver); createAllPdpList(); @@ -351,6 +246,31 @@ final class DataConnectionTracker extends Handler noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; } + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForAvailable(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + ((GSMPhone) phone).mSIMRecords.unregisterForRecordsLoaded(this); + phone.mCM.unregisterForDataStateChanged(this); + ((GSMPhone) phone).mCT.unregisterForVoiceCallEnded(this); + ((GSMPhone) phone).mCT.unregisterForVoiceCallStarted(this); + ((GSMPhone) phone).mSST.unregisterForGprsAttached(this); + ((GSMPhone) phone).mSST.unregisterForGprsDetached(this); + ((GSMPhone) phone).mSST.unregisterForRoamingOn(this); + ((GSMPhone) phone).mSST.unregisterForRoamingOff(this); + ((GSMPhone) phone).mSST.unregisterForPsRestrictedEnabled(this); + ((GSMPhone) phone).mSST.unregisterForPsRestrictedDisabled(this); + + phone.getContext().unregisterReceiver(this.mIntentReceiver); + phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver); + + destroyAllPdpList(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized"); + } + void setState(State s) { if (DBG) log ("setState: " + s); if (state != s) { @@ -375,19 +295,6 @@ final class DataConnectionTracker extends Handler } } - 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) { @@ -399,7 +306,7 @@ final class DataConnectionTracker extends Handler return result; } - String getActiveApnString() { + protected String getActiveApnString() { String result = null; if (mActiveApn != null) { result = mActiveApn.apn; @@ -409,18 +316,20 @@ final class DataConnectionTracker extends Handler /** * Ensure that we are connected to an APN of the specified type. - * @param type the APN type (currently the only valid value - * is {@link Phone#APN_TYPE_MMS}) + * @param type the APN type (currently the only valid values + * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) * @return the result of the operation. Success is indicated by * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast * will be sent by the ConnectivityManager when a connection to * the APN has been established. */ - int enableApnType(String type) { - if (!TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + protected int enableApnType(String type) { + if (!TextUtils.equals(type, Phone.APN_TYPE_MMS) && + !TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { return Phone.APN_REQUEST_FAILED; } + // If already active, return Log.d(LOG_TAG, "enableApnType("+type+")"); if (isApnTypeActive(type)) { @@ -453,12 +362,15 @@ final class DataConnectionTracker extends Handler * The APN of the specified type is no longer needed. Ensure that if * use of the default APN has not been explicitly disabled, we are connected * to the default APN. - * @param type the APN type. The only valid value currently is {@link Phone#APN_TYPE_MMS}. + * @param type the APN type. The only valid values are currently + * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. * @return */ - int disableApnType(String type) { + protected int disableApnType(String type) { Log.d(LOG_TAG, "disableApnType("+type+")"); - if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + if ((TextUtils.equals(type, Phone.APN_TYPE_MMS) || + TextUtils.equals(type, Phone.APN_TYPE_SUPL)) + && isEnabled(type)) { removeMessages(EVENT_RESTORE_DEFAULT_APN); setEnabled(type, false); if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { @@ -489,16 +401,15 @@ final class DataConnectionTracker extends Handler * 2. registered to gprs service * 3. user doesn't explicitly disable data service * 4. wifi is not on - * 5. packet service is not restricted * * @return false while no data connection if all above requirements are met. */ - boolean isDataConnectionAsDesired() { + public boolean isDataConnectionAsDesired() { boolean roaming = phone.getServiceState().getRoaming(); - if (phone.mSIMRecords.getRecordsLoaded() && - phone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && - (!roaming || getDataOnRoamingEnabled()) && + if (((GSMPhone) phone).mSIMRecords.getRecordsLoaded() && + ((GSMPhone) phone).mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && + (!roaming || getDataOnRoamingEnabled()) && !mIsWifiConnected && !mIsPsRestricted ) { return (state == State.CONNECTED); @@ -527,6 +438,8 @@ final class DataConnectionTracker extends Handler return dataEnabled[APN_DEFAULT_ID]; } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) { return dataEnabled[APN_MMS_ID]; + } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) { + return dataEnabled[APN_SUPL_ID]; } else { return false; } @@ -538,9 +451,12 @@ final class DataConnectionTracker extends Handler dataEnabled[APN_DEFAULT_ID] = enable; } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) { dataEnabled[APN_MMS_ID] = enable; + } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) { + dataEnabled[APN_SUPL_ID] = enable; } Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] + - " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID]); + " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID] + + " dataEnabled[SUPL_APN]=" + dataEnabled[APN_SUPL_ID]); } /** @@ -564,17 +480,20 @@ final class DataConnectionTracker extends Handler return trySetupData(Phone.REASON_DATA_ENABLED); } else if (!enable) { setEnabled(Phone.APN_TYPE_DEFAULT, false); - // Don't tear down if there is an active APN and it handles MMS. + // Don't tear down if there is an active APN and it handles MMS or SUPL. // TODO: This isn't very general. - if (!isApnTypeActive(Phone.APN_TYPE_MMS) || !isEnabled(Phone.APN_TYPE_MMS)) { - cleanUpConnection(true, Phone.REASON_DATA_DISABLED); - return true; + if ((isApnTypeActive(Phone.APN_TYPE_MMS) && isEnabled(Phone.APN_TYPE_MMS)) || + (isApnTypeActive(Phone.APN_TYPE_SUPL) && isEnabled(Phone.APN_TYPE_SUPL))) { + return false; } - return false; - } else // isEnabled && enable + cleanUpConnection(true, Phone.REASON_DATA_DISABLED); + return true; + } else { + // isEnabled && enable return true; + } } - + /** * Simply tear down data connections due to radio off * and don't setup again. @@ -582,7 +501,7 @@ final class DataConnectionTracker extends Handler public void cleanConnectionBeforeRadioOff() { cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); } - + /** * Report the current state of data connectivity (enabled or disabled) for * the default APN. @@ -599,34 +518,14 @@ final class DataConnectionTracker extends Handler * {@code true} otherwise. */ public boolean getAnyDataEnabled() { - return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID]; - } - - //The data roaming setting is now located in the shared preferences. - // See if the requested preference value is the same as that stored in - // the shared values. If it is not, then update it. - public void setDataOnRoamingEnabled(boolean enabled) { - if (getDataOnRoamingEnabled() != enabled) { - 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); - sendMessage(roamingMsg); - } - - //Retrieve the data roaming setting from the shared preferences. - public boolean getDataOnRoamingEnabled() { - try { - return Settings.Secure.getInt(phone.getContext().getContentResolver(), - Settings.Secure.DATA_ROAMING) > 0; - } catch (SettingNotFoundException snfe) { - return false; - } + return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]; } - public ArrayList getAllPdps() { - ArrayList pdps = (ArrayList)pdpList.clone(); + /** + * Formerly this method was ArrayList getAllPdps() + */ + public ArrayList getAllDataConnections() { + ArrayList pdps = (ArrayList)pdpList.clone(); return pdps; } @@ -640,8 +539,7 @@ final class DataConnectionTracker extends Handler * Invoked when ServiceStateTracker observes a transition from GPRS * attach to detach. */ - private void onGprsDetached() - { + protected void onGprsDetached() { /* * We presently believe it is unnecessary to tear down the PDP context * when GPRS detaches, but we should stop the network polling. @@ -663,8 +561,7 @@ final class DataConnectionTracker extends Handler } } - private boolean trySetupData(String reason) - { + private boolean trySetupData(String reason) { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); @@ -679,13 +576,14 @@ final class DataConnectionTracker extends Handler return true; } - int gprsState = phone.mSST.getCurrentGprsState(); + int gprsState = ((GSMPhone) phone).mSST.getCurrentGprsState(); boolean roaming = phone.getServiceState().getRoaming(); if ((state == State.IDLE || state == State.SCANNING) && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) - && phone.mSIMRecords.getRecordsLoaded() - && phone.getState() == Phone.State.IDLE + && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() + && ( ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() || + phone.getState() == Phone.State.IDLE ) && isDataAllowed() && !mIsPsRestricted ) { @@ -693,7 +591,7 @@ final class DataConnectionTracker extends Handler waitingApns = buildWaitingApns(); if (waitingApns.isEmpty()) { if (DBG) log("No APN found"); - notifyNoData(PdpConnection.PdpFailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.BAD_APN); return false; } else { log ("Create from allApns : " + apnListToString(allApns)); @@ -709,8 +607,8 @@ final class DataConnectionTracker extends Handler log("trySetupData: Not ready for data: " + " dataState=" + state + " gprsState=" + gprsState + - " sim=" + phone.mSIMRecords.getRecordsLoaded() + - " UMTS=" + phone.mSST.isConcurrentVoiceAndData() + + " sim=" + ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() + + " UMTS=" + ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() + " phoneState=" + phone.getState() + " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + @@ -740,7 +638,8 @@ final class DataConnectionTracker extends Handler mReconnectIntent = null; } - for (PdpConnection pdp : pdpList) { + for (DataConnection conn : pdpList) { + PdpConnection pdp = (PdpConnection) conn; if (tearDown) { Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); pdp.disconnect(msg); @@ -762,7 +661,7 @@ final class DataConnectionTracker extends Handler * 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); @@ -814,8 +713,9 @@ final class DataConnectionTracker extends Handler } private PdpConnection findFreePdp() { - for (PdpConnection pdp : pdpList) { - if (pdp.getState() == PdpConnection.PdpState.INACTIVE) { + for (DataConnection conn : pdpList) { + PdpConnection pdp = (PdpConnection) conn; + if (pdp.getState() == DataConnection.State.INACTIVE) { return pdp; } } @@ -854,7 +754,7 @@ final class DataConnectionTracker extends Handler return null; } - String getIpAddress(String apnType) { + protected String getIpAddress(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getIpAddress(); @@ -870,7 +770,7 @@ final class DataConnectionTracker extends Handler return null; } - String[] getDnsServers(String apnType) { + protected String[] getDnsServers(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getDnsServers(); @@ -879,8 +779,7 @@ final class DataConnectionTracker extends Handler } private boolean - pdpStatesHasCID (ArrayList states, int cid) - { + pdpStatesHasCID (ArrayList states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return true; } @@ -889,10 +788,9 @@ final class DataConnectionTracker extends Handler } private boolean - pdpStatesHasActiveCID (ArrayList states, int cid) - { + pdpStatesHasActiveCID (ArrayList states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { - if (states.get(i).cid == cid) return states.get(i).active; + if (states.get(i).cid == cid) return (states.get(i).active != 0); } return false; @@ -907,7 +805,7 @@ final class DataConnectionTracker extends Handler isConnected = (state != State.IDLE && state != State.FAILED); // The "current" may no longer be valid. MMS depends on this to send properly. - phone.updateCurrentCarrierInProvider(); + ((GSMPhone) phone).updateCurrentCarrierInProvider(); // TODO: It'd be nice to only do this if the changed entrie(s) // match the current operator. @@ -926,9 +824,7 @@ final class DataConnectionTracker extends Handler * via an unsolicited response (which could have happened at any * previous state */ - private void - onPdpStateChanged (AsyncResult ar, boolean explicitPoll) - { + protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) { ArrayList pdpStates; pdpStates = (ArrayList)(ar.result); @@ -940,57 +836,38 @@ final class DataConnectionTracker extends Handler return; } - - // This is how things are supposed to work: - // The PDP list is supposed to be empty of the CID - // when it disconnects - - if (state == State.CONNECTED - && !pdpStatesHasCID(pdpStates, cidActive)) { - - // It looks like the PDP context has deactivated - // Tear everything down and try to reconnect - - Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting"); - - // Add an event log when the network drops PDP - int cid = -1; - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); - if (loc != null) cid = loc.getCid(); - - EventLog.List val = new EventLog.List(cid, - TelephonyManager.getDefault().getNetworkType()); - - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); - - cleanUpConnection(true, null); - - return; - } - - if (true) { - // - // Workaround for issue #655426 - // - - // -------------------------- - - // This is how some things work now: the PDP context is still - // listed with active = false, which makes it hard to - // distinguish an activating context from an activated-and-then - // deactivated one. - // - // Here, we only consider this authoritative if we asked for the - // PDP list. If it was an unsolicited response, we poll again - // to make sure everyone agrees on the initial state - - if (state == State.CONNECTED - && !pdpStatesHasActiveCID(pdpStates, cidActive)) { + if (state == State.CONNECTED) { + // The way things are supposed to work, the PDP list + // should not contain the CID after it disconnects. + // However, the way things really work, sometimes the PDP + // context is still listed with active = false, which + // makes it hard to distinguish an activating context from + // an activated-and-then deactivated one. + if (!pdpStatesHasCID(pdpStates, cidActive)) { + // It looks like the PDP context has deactivated. + // Tear everything down and try to reconnect. + + Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting"); + + // Add an event log when the network drops PDP + int cid = -1; + GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + if (loc != null) cid = loc.getCid(); + EventLog.List val = new EventLog.List(cid, + TelephonyManager.getDefault().getNetworkType()); + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); + + cleanUpConnection(true, null); + return; + } else if (!pdpStatesHasActiveCID(pdpStates, cidActive)) { + // Here, we only consider this authoritative if we asked for the + // PDP list. If it was an unsolicited response, we poll again + // to make sure everyone agrees on the initial state. if (!explicitPoll) { // We think it disconnected but aren't sure...poll from our side phone.mCM.getPDPContextList( - this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); } else { Log.i(LOG_TAG, "PDP connection has dropped (active=false case). " + " Reconnecting"); @@ -999,10 +876,8 @@ final class DataConnectionTracker extends Handler int cid = -1; GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); if (loc != null) cid = loc.getCid(); - EventLog.List val = new EventLog.List(cid, TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); cleanUpConnection(true, null); @@ -1062,9 +937,7 @@ final class DataConnectionTracker extends Handler * with certain RIL impl's/basebands * */ - private void - startPeriodicPdpPoll() - { + private void startPeriodicPdpPoll() { removeMessages(EVENT_POLL_PDP); sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); @@ -1074,6 +947,7 @@ final class DataConnectionTracker extends Handler txPkts = -1; rxPkts = -1; sentSinceLastRecv = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; mNoRecvPollCount = 0; } @@ -1089,16 +963,14 @@ final class DataConnectionTracker extends Handler } else { mPdpResetCount = 0; EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv); - phone.mSST.reRegisterNetwork(null); + ((GSMPhone) phone).mSST.reRegisterNetwork(null); } // TODO: Add increasingly drastic recovery steps, eg, // reset the radio, reset the device. } } - private void - startNetStatPoll() - { + protected void startNetStatPoll() { if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) { Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); resetPollStats(); @@ -1107,17 +979,13 @@ final class DataConnectionTracker extends Handler } } - private void - stopNetStatPoll() - { + protected void stopNetStatPoll() { netStatPollEnabled = false; removeCallbacks(mPollNetStat); Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); } - private void - restartRadio() - { + protected void restartRadio() { Log.d(LOG_TAG, "************TURN OFF RADIO**************"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); phone.mCM.setRadioPower(false, null); @@ -1133,7 +1001,7 @@ final class DataConnectionTracker extends Handler SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); } - Runnable mPollNetStat = new Runnable() + private Runnable mPollNetStat = new Runnable() { public void run() { @@ -1164,7 +1032,7 @@ final class DataConnectionTracker extends Handler newActivity = Activity.DATAINANDOUT; mPdpResetCount = 0; } else if (sent > 0 && received == 0) { - if (phone.mCT.state == Phone.State.IDLE) { + if (phone.getState() == Phone.State.IDLE) { sentSinceLastRecv += sent; } else { sentSinceLastRecv = 0; @@ -1188,7 +1056,8 @@ final class DataConnectionTracker extends Handler } int watchdogTrigger = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG); + Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, + NUMBER_SENT_PACKETS_OF_HANG); if (sentSinceLastRecv >= watchdogTrigger) { // we already have NUMBER_SENT_PACKETS sent without ack @@ -1204,13 +1073,14 @@ final class DataConnectionTracker extends Handler // It's possible the PDP context went down and we weren't notified. // Start polling the context list in an attempt to recover. if (DBG) log("no DATAIN in a while; polling PDP"); - phone.mCM.getPDPContextList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + phone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); mNoRecvPollCount++; // Slow down the poll interval to let things happen netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS); + Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, + POLL_NETSTAT_SLOW_MILLIS); } else { if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + " pkts since last received"); @@ -1242,7 +1112,7 @@ final class DataConnectionTracker extends Handler } } }; - + private void runPingTest () { int status = -1; try { @@ -1279,15 +1149,13 @@ final class DataConnectionTracker extends Handler * seems like it deserves an error notification. * Transient errors are ignored */ - private boolean - shouldPostNotification(PdpConnection.PdpFailCause cause) - { + private boolean shouldPostNotification(PdpConnection.FailCause cause) { boolean shouldPost = true; // TODO CHECK // if (dataLink != null) { // shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED; //} - return (shouldPost && cause != PdpConnection.PdpFailCause.UNKNOWN); + return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN); } /** @@ -1301,14 +1169,13 @@ final class DataConnectionTracker extends Handler boolean retry = true; if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || - Phone.REASON_DATA_DISABLED.equals(reason) || - Phone.REASON_PS_RESTRICT_ENABLED.equals(reason)) { + Phone.REASON_DATA_DISABLED.equals(reason) ) { retry = false; } return retry; - } - - private void reconnectAfterFail(PdpFailCause lastFailCauseCode, String reason) { + } + + private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -1338,314 +1205,215 @@ final class DataConnectionTracker extends Handler } } - private void notifyNoData(PdpConnection.PdpFailCause lastFailCauseCode) { + private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) { setState(State.FAILED); } - - private void log(String s) { - Log.d(LOG_TAG, "[DataConnectionTracker] " + s); + protected void onRecordsLoaded() { + createAllApnList(); + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); } - //***** Overridden from Handler - public void - handleMessage (Message msg) - { - AsyncResult ar; - String reason = null; - - switch (msg.what) { - case EVENT_RECORDS_LOADED: - createAllApnList(); - if (state == State.FAILED) { - cleanUpConnection(false, null); - } - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); - break; - - case EVENT_ENABLE_NEW_APN: - // TODO: To support simultaneous PDP contexts, this should really only call - // cleanUpConnection if it needs to free up a PdpConnection. - reason = Phone.REASON_APN_SWITCHED; - cleanUpConnection(true, reason); - break; - - case EVENT_TRY_SETUP_DATA: - if (msg.obj instanceof String) { - reason = (String)msg.obj; - } - - trySetupData(reason); - break; - - case EVENT_RESTORE_DEFAULT_APN: - if (DBG) Log.d(LOG_TAG, "Restore default APN"); - setEnabled(Phone.APN_TYPE_MMS, false); - if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); - mRequestedApnType = Phone.APN_TYPE_DEFAULT; - } - break; - - case EVENT_ROAMING_OFF: - trySetupData(Phone.REASON_ROAMING_OFF); - break; + protected void onEnableNewApn() { + // TODO: To support simultaneous PDP contexts, this should really only call + // cleanUpConnection if it needs to free up a PdpConnection. + cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + } - case EVENT_GPRS_DETACHED: - onGprsDetached(); - break; + protected void onTrySetupData() { + trySetupData(null); + } - case EVENT_GPRS_ATTACHED: - onGprsAttached(); - break; + protected void onRestoreDefaultApn() { + if (DBG) Log.d(LOG_TAG, "Restore default APN"); + setEnabled(Phone.APN_TYPE_MMS, false); - case EVENT_ROAMING_ON: - if (getDataOnRoamingEnabled()) { - trySetupData(Phone.REASON_ROAMING_ON); - } else { - if (DBG) log("Tear down data connection on roaming."); - cleanUpConnection(true, Phone.REASON_ROAMING_ON); - } - break; + if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); + mRequestedApnType = Phone.APN_TYPE_DEFAULT; + } + } - case EVENT_RADIO_AVAILABLE: - if (phone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - setState(State.CONNECTED); - phone.notifyDataConnection(null); + protected void onRoamingOff() { + trySetupData(Phone.REASON_ROAMING_OFF); + } + protected void onRoamingOn() { + if (getDataOnRoamingEnabled()) { + trySetupData(Phone.REASON_ROAMING_ON); + } else { + if (DBG) log("Tear down data connection on roaming."); + cleanUpConnection(true, Phone.REASON_ROAMING_ON); + } + } - Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); - } + protected void onRadioAvailable() { + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(null); - if (state != State.IDLE) { - cleanUpConnection(true, null); - } - break; + Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + } - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - // Make sure our reconnect delay starts at the initial value - // next time the radio comes on - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + if (state != State.IDLE) { + cleanUpConnection(true, null); + } + } - if (phone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); - } else { - if (DBG) log("Radio is off and clean up all connection"); - // TODO: Should we reset mRequestedApnType to "default"? - cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); - } - break; + protected void onRadioOffOrNotAvailable() { + // Make sure our reconnect delay starts at the initial value + // next time the radio comes on + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - case EVENT_DATA_SETUP_COMPLETE: - ar = (AsyncResult) msg.obj; - if (ar.userObj instanceof String) { - reason = (String) ar.userObj; - } + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + } else { + if (DBG) log("Radio is off and clean up all connection"); + // TODO: Should we reset mRequestedApnType to "default"? + cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); + } + } - if (ar.exception == null) { - // everything is setup - - // arg1 contains CID for this PDP context - cidActive = msg.arg1; - /* - * We may have switched away from the default PDP context - * in order to enable a "special" APN (e.g., for MMS - * traffic). Set a timer to switch back and/or disable the - * special APN, so that a negligient application doesn't - * permanently prevent data connectivity. What we are - * protecting against here is not malicious apps, but - * rather an app that inadvertantly fails to reset to the - * default APN, or that dies before doing so. - */ - if (dataEnabled[APN_MMS_ID]) { - removeMessages(EVENT_RESTORE_DEFAULT_APN); - sendMessageDelayed( - obtainMessage(EVENT_RESTORE_DEFAULT_APN), - getRestoreDefaultApnDelay()); - } - if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - SystemProperties.set("gsm.defaultpdpcontext.active", "true"); + protected void onDataSetupComplete(AsyncResult ar) { + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + + if (ar.exception == null) { + // everything is setup + + /* + * We may have switched away from the default PDP context + * in order to enable a "special" APN (e.g., for MMS + * traffic). Set a timer to switch back and/or disable the + * special APN, so that a negligient application doesn't + * permanently prevent data connectivity. What we are + * protecting against here is not malicious apps, but + * rather an app that inadvertantly fails to reset to the + * default APN, or that dies before doing so. + */ + if (dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]) { + removeMessages(EVENT_RESTORE_DEFAULT_APN); + sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN), + getRestoreDefaultApnDelay()); + } + if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + SystemProperties.set("gsm.defaultpdpcontext.active", "true"); if (canSetPreferApn && preferredApn == null) { Log.d(LOG_TAG, "PREFERED APN is null"); preferredApn = mActiveApn; setPreferredApn(preferredApn.id); } - } else { - SystemProperties.set("gsm.defaultpdpcontext.active", "false"); - } - notifyDefaultData(reason); + } else { + SystemProperties.set("gsm.defaultpdpcontext.active", "false"); + } + notifyDefaultData(reason); - // TODO: For simultaneous PDP support, we need to build another - // trigger another TRY_SETUP_DATA for the next APN type. (Note - // that the existing connection may service that type, in which - // case we should try the next type, etc. - } else { - PdpConnection.PdpFailCause cause; - cause = (PdpConnection.PdpFailCause) (ar.result); - if(DBG) - log("PDP setup failed " + cause); + // TODO: For simultaneous PDP support, we need to build another + // trigger another TRY_SETUP_DATA for the next APN type. (Note + // that the existing connection may service that type, in which + // case we should try the next type, etc. + } else { + PdpConnection.FailCause cause; + cause = (PdpConnection.FailCause) (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(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); - } - // No try for permanent failure - if (cause.isPermanentFail()) { - notifyNoData(cause); - } + if (cause == PdpConnection.FailCause.BAD_APN || + cause == PdpConnection.FailCause.BAD_PAP_SECRET || + cause == PdpConnection.FailCause.BARRED || + cause == PdpConnection.FailCause.RADIO_ERROR_RETRY || + cause == PdpConnection.FailCause.SUSPENED_TEMPORARY || + cause == PdpConnection.FailCause.UNKNOWN || + cause == PdpConnection.FailCause.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(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); + } - if (tryNextApn(cause)) { - waitingApns.remove(0); - if (waitingApns.isEmpty()) { - // No more to try, start delayed retry - startDelayedRetry(cause, reason); - } else { - // we still have more apns to try - setState(State.SCANNING); - // Wait a bit before trying the next APN, so that - // we're not tying up the RIL command channel - sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), - RECONNECT_DELAY_INITIAL_MILLIS); - } - } else { - startDelayedRetry(cause, reason); - } - } - break; + // No try for permanent failure + if (cause.isPermanentFail()) { + notifyNoData(cause); + } - case EVENT_DISCONNECT_DONE: - if(DBG) log("EVENT_DISCONNECT_DONE"); - ar = (AsyncResult) msg.obj; - if (ar.userObj instanceof String) { - reason = (String) ar.userObj; - } - setState(State.IDLE); - phone.notifyDataConnection(reason); - mActiveApn = null; - if ( retryAfterDisconnected(reason) ) { + if (tryNextApn(cause)) { + waitingApns.remove(0); + if (waitingApns.isEmpty()) { + // No more to try, start delayed retry + startDelayedRetry(cause, reason); + } else { + // we still have more apns to try + setState(State.SCANNING); trySetupData(reason); } - break; - - case EVENT_PDP_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - - onPdpStateChanged(ar, false); - break; - - case EVENT_GET_PDP_LIST_COMPLETE: - ar = (AsyncResult) msg.obj; - - onPdpStateChanged(ar, true); - break; - - case EVENT_POLL_PDP: - /* See comment in startPeriodicPdpPoll */ - ar = (AsyncResult) msg.obj; - - if (!(state == State.CONNECTED)) { - // not connected; don't poll anymore - break; - } - - phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + } else { + startDelayedRetry(cause, reason); + } + } + } - sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), - POLL_PDP_MILLIS); - break; + protected void onDisconnectDone(AsyncResult ar) { + String reason = null; + if(DBG) log("EVENT_DISCONNECT_DONE"); + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + setState(State.IDLE); + phone.notifyDataConnection(reason); + mActiveApn = null; + if (retryAfterDisconnected(reason)) { + trySetupData(reason); + } + } - case EVENT_VOICE_CALL_STARTED: - if (state == State.CONNECTED && - !phone.mSST.isConcurrentVoiceAndData()) { - stopNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); - } - break; + protected void onPollPdp() { + if (state == State.CONNECTED) { + // only poll when connected + phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); + } + } - case EVENT_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 { - // in case data setup was attempted when we were on a voice call - trySetupData(Phone.REASON_VOICE_CALL_ENDED); - } - break; + protected void onVoiceCallStarted() { + if (state == State.CONNECTED && !((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { + stopNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + } + } - case EVENT_START_NETSTAT_POLL: - mPingTestActive = false; + protected void onVoiceCallEnded() { + if (state == State.CONNECTED) { + if (!((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { startNetStatPoll(); - break; - - case EVENT_START_RECOVERY: - mPingTestActive = false; - doRecovery(); - break; - - case EVENT_APN_CHANGED: - onApnChanged(); - break; - - case EVENT_PS_RESTRICT_ENABLED: - /** - * We don't need to explicitly to tear down the PDP context - * when PS restricted is enabled. The base band will deactive - * PDP context and notify us with PDP_CONTEXT_CHANGED. - * But we should stop the network polling and prevent reset PDP. - */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); - stopNetStatPoll(); - mIsPsRestricted = true; - break; - - case EVENT_PS_RESTRICT_DISABLED: - /** - * When PS restrict is removed, we need setup PDP connection if - * PDP connection is down. - */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); - mIsPsRestricted = false; - if (state == State.CONNECTED) { - startNetStatPoll(); - } else { - if (state == State.FAILED) { - cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - } - trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); - } - break; - + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + } else { + // clean slate after call end. + resetPollStats(); + } + } else { + // in case data setup was attempted when we were on a voice call + trySetupData(Phone.REASON_VOICE_CALL_ENDED); } } - private boolean tryNextApn(PdpFailCause cause) { - return (cause != PdpFailCause.RADIO_NOT_AVIALABLE) - && (cause != PdpFailCause.RADIO_OFF) - && (cause != PdpFailCause.RADIO_ERROR_RETRY) - && (cause != PdpFailCause.NO_SIGNAL) - && (cause != PdpFailCause.SIM_LOCKED); + private boolean tryNextApn(FailCause cause) { + return (cause != FailCause.RADIO_NOT_AVAILABLE) + && (cause != FailCause.RADIO_OFF) + && (cause != FailCause.RADIO_ERROR_RETRY) + && (cause != FailCause.NO_SIGNAL) + && (cause != FailCause.SIM_LOCKED); } private int getRestoreDefaultApnDelay() { @@ -1668,7 +1436,7 @@ final class DataConnectionTracker extends Handler */ private void createAllApnList() { allApns = new ArrayList(); - String operator = phone.mSIMRecords.getSIMOperatorNumeric(); + String operator = ((GSMPhone) phone).mSIMRecords.getSIMOperatorNumeric(); if (operator != null) { String selection = "numeric = '" + operator + "'"; @@ -1694,7 +1462,7 @@ final class DataConnectionTracker extends Handler if (allApns.isEmpty()) { if (DBG) log("No APN found for carrier: " + operator); preferredApn = null; - notifyNoData(PdpConnection.PdpFailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.BAD_APN); } else { preferredApn = getPreferredApn(); Log.d(LOG_TAG, "Get PreferredAPN"); @@ -1706,15 +1474,22 @@ final class DataConnectionTracker extends Handler } private void createAllPdpList() { - pdpList = new ArrayList(); - PdpConnection pdp; + pdpList = new ArrayList(); + DataConnection pdp; for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { - pdp = new PdpConnection(phone); + pdp = new PdpConnection((GSMPhone) phone); pdpList.add(pdp); } } + private void destroyAllPdpList() { + if(pdpList != null) { + PdpConnection pdp; + pdpList.removeAll(pdpList); + } + } + /** * * @return waitingApns list to be used to create PDP @@ -1722,7 +1497,7 @@ final class DataConnectionTracker extends Handler */ private ArrayList buildWaitingApns() { ArrayList apnList = new ArrayList(); - String operator = phone.mSIMRecords.getSIMOperatorNumeric(); + String operator = ((GSMPhone )phone).mSIMRecords.getSIMOperatorNumeric(); if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { if (canSetPreferApn && preferredApn != null) { @@ -1775,7 +1550,7 @@ final class DataConnectionTracker extends Handler return result.toString(); } - private void startDelayedRetry(PdpConnection.PdpFailCause cause, String reason) { + private void startDelayedRetry(PdpConnection.FailCause cause, String reason) { notifyNoData(cause); if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) { sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN)); @@ -1833,4 +1608,95 @@ final class DataConnectionTracker extends Handler return null; } + + public void handleMessage (Message msg) { + + switch (msg.what) { + case EVENT_RECORDS_LOADED: + onRecordsLoaded(); + break; + + case EVENT_ENABLE_NEW_APN: + onEnableNewApn(); + break; + + case EVENT_RESTORE_DEFAULT_APN: + onRestoreDefaultApn(); + break; + + case EVENT_GPRS_DETACHED: + onGprsDetached(); + break; + + case EVENT_GPRS_ATTACHED: + onGprsAttached(); + break; + + case EVENT_DATA_STATE_CHANGED: + onPdpStateChanged((AsyncResult) msg.obj, false); + break; + + case EVENT_GET_PDP_LIST_COMPLETE: + onPdpStateChanged((AsyncResult) msg.obj, true); + break; + + case EVENT_POLL_PDP: + onPollPdp(); + break; + + case EVENT_START_NETSTAT_POLL: + mPingTestActive = false; + startNetStatPoll(); + break; + + case EVENT_START_RECOVERY: + mPingTestActive = false; + doRecovery(); + break; + + case EVENT_APN_CHANGED: + onApnChanged(); + break; + + case EVENT_PS_RESTRICT_ENABLED: + /** + * We don't need to explicitly to tear down the PDP context + * when PS restricted is enabled. The base band will deactive + * PDP context and notify us with PDP_CONTEXT_CHANGED. + * But we should stop the network polling and prevent reset PDP. + */ + Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); + stopNetStatPoll(); + mIsPsRestricted = true; + break; + + case EVENT_PS_RESTRICT_DISABLED: + /** + * When PS restrict is removed, we need setup PDP connection if + * PDP connection is down. + */ + Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); + mIsPsRestricted = false; + if (state == State.CONNECTED) { + startNetStatPoll(); + } else { + if (state == State.FAILED) { + cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } + trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); + } + break; + + default: + // handle the message in the super class DataConnectionTracker + super.handleMessage(msg); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s); + } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 04f8332f56dabcc75275e96314deeb4207699a19..4db8fc64f8c0c896ff44aa0891b13af95fea46bd 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -18,39 +18,40 @@ package com.android.internal.telephony.gsm; import android.content.Context; import com.android.internal.telephony.*; + import android.os.*; -import android.os.AsyncResult; +import android.telephony.PhoneNumberUtils; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.util.Log; + +import static com.android.internal.telephony.CommandsInterface.*; + import java.util.regex.Pattern; import java.util.regex.Matcher; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.telephony.PhoneNumberUtils; -import static com.android.internal.telephony.gsm.CommandsInterface.*; /** * The motto for this file is: * - * "NOTE: By using the # as a separator, most cases are expected to be unambiguous." + * "NOTE: By using the # as a separator, most cases are expected to be unambiguous." * -- TS 22.030 6.5.2 * * {@hide} * */ -public final class GsmMmiCode extends Handler implements MmiCode -{ +public final class GsmMmiCode extends Handler implements MmiCode { static final String LOG_TAG = "GSM"; //***** Constants - + // From TS 22.030 6.5.2 static final String ACTION_ACTIVATE = "*"; static final String ACTION_DEACTIVATE = "#"; static final String ACTION_INTERROGATE = "*#"; static final String ACTION_REGISTER = "**"; static final String ACTION_ERASURE = "##"; - - // Supp Service cocdes from TS 22.030 Annex B + + // Supp Service cocdes from TS 22.030 Annex B //Called line presentation static final String SC_CLIP = "30"; @@ -102,25 +103,24 @@ public final class GsmMmiCode extends Handler implements MmiCode GSMPhone phone; Context context; - + String action; // One of ACTION_* String sc; // Service Code String sia, sib, sic; // Service Info a,b,c String poundString; // Entire MMI string up to and including # String dialingNumber; String pwd; // For password registration - - /** Set to true in processCode, not at newFromDialString time */ + /** Set to true in processCode, not at newFromDialString time */ private boolean isPendingUSSD; private boolean isUssdRequest; - State state = State.PENDING; + State state = State.PENDING; CharSequence message; - + //***** Class Variables - + // See TS 22.030 6.5.2 "Structure of the MMI" @@ -137,9 +137,9 @@ public final class GsmMmiCode extends Handler implements MmiCode 10 = dialing number */ - static final int MATCH_GROUP_POUND_STRING = 1; + static final int MATCH_GROUP_POUND_STRING = 1; - static final int MATCH_GROUP_ACTION = 2; + static final int MATCH_GROUP_ACTION = 2; //(activation/interrogation/registration/erasure) static final int MATCH_GROUP_SERVICE_CODE = 3; @@ -151,7 +151,7 @@ public final class GsmMmiCode extends Handler implements MmiCode //***** Public Class methods - + /** * Some dial strings in GSM are defined to do non-call setup * things, such as modify or query supplementry service settings (eg, call @@ -165,9 +165,8 @@ public final class GsmMmiCode extends Handler implements MmiCode * Please see flow chart in TS 22.030 6.5.3.2 */ - static GsmMmiCode - newFromDialString(String dialString, GSMPhone phone) - { + static GsmMmiCode + newFromDialString(String dialString, GSMPhone phone) { Matcher m; GsmMmiCode ret = null; @@ -187,7 +186,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } else if (dialString.endsWith("#")) { // TS 22.030 sec 6.5.3.2 - // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet + // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet // (up to the maximum defined in 3GPP TS 24.080 [10]), followed by #SEND". ret = new GsmMmiCode(phone); @@ -202,16 +201,15 @@ public final class GsmMmiCode extends Handler implements MmiCode } static GsmMmiCode - newNetworkInitiatedUssd (String ussdMessage, - boolean isUssdRequest, GSMPhone phone) - { + newNetworkInitiatedUssd (String ussdMessage, + boolean isUssdRequest, GSMPhone phone) { GsmMmiCode ret; ret = new GsmMmiCode(phone); ret.message = ussdMessage; ret.isUssdRequest = isUssdRequest; - + // If it's a request, set to PENDING so that it's cancelable. if (isUssdRequest) { ret.isPendingUSSD = true; @@ -225,42 +223,39 @@ public final class GsmMmiCode extends Handler implements MmiCode static GsmMmiCode newFromUssdUserInput(String ussdMessge, GSMPhone phone) { GsmMmiCode ret = new GsmMmiCode(phone); - + ret.message = ussdMessge; ret.state = State.PENDING; ret.isPendingUSSD = true; - + return ret; } //***** Private Class methods - /** make empty strings be null. - * Regexp returns empty strings for empty groups + /** make empty strings be null. + * Regexp returns empty strings for empty groups */ private static String - makeEmptyNull (String s) - { + makeEmptyNull (String s) { if (s != null && s.length() == 0) return null; return s; } /** returns true of the string is empty or null */ - private static boolean - isEmptyOrNull(CharSequence s) - { + private static boolean + isEmptyOrNull(CharSequence s) { return s == null || (s.length() == 0); } private static int - scToCallForwardReason(String sc) - { - if (sc == null) { + scToCallForwardReason(String sc) { + if (sc == null) { throw new RuntimeException ("invalid call forward sc"); } - + if (sc.equals(SC_CF_All)) { return CommandsInterface.CF_REASON_ALL; } else if (sc.equals(SC_CFU)) { @@ -279,8 +274,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } private static int - siToServiceClass(String si) - { + siToServiceClass(String si) { if (si == null || si.length() == 0) { return SERVICE_CLASS_NONE; } else { @@ -299,7 +293,7 @@ public final class GsmMmiCode extends Handler implements MmiCode /* Note for code 20: From TS 22.030 Annex C: - "All GPRS bearer services" are not included in "All tele and bearer services" + "All GPRS bearer services" are not included in "All tele and bearer services" and "All bearer services"." ....so SERVICE_CLASS_DATA, which (according to 27.007) includes GPRS */ @@ -319,8 +313,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } private static int - siToTime (String si) - { + siToTime (String si) { if (si == null || si.length() == 0) { return 0; } else { @@ -330,33 +323,30 @@ public final class GsmMmiCode extends Handler implements MmiCode } static boolean - isServiceCodeCallForwarding(String sc) - { - return sc != null && - (sc.equals(SC_CFU) - || sc.equals(SC_CFB) || sc.equals(SC_CFNRy) - || sc.equals(SC_CFNR) || sc.equals(SC_CF_All) + isServiceCodeCallForwarding(String sc) { + return sc != null && + (sc.equals(SC_CFU) + || sc.equals(SC_CFB) || sc.equals(SC_CFNRy) + || sc.equals(SC_CFNR) || sc.equals(SC_CF_All) || sc.equals(SC_CF_All_Conditional)); } static boolean - isServiceCodeCallBarring(String sc) - { + isServiceCodeCallBarring(String sc) { return sc != null && - (sc.equals(SC_BAOC) + (sc.equals(SC_BAOC) || sc.equals(SC_BAOIC) || sc.equals(SC_BAOICxH) || sc.equals(SC_BAIC) || sc.equals(SC_BAICr) || sc.equals(SC_BA_ALL) || sc.equals(SC_BA_MO) - || sc.equals(SC_BA_MT)); + || sc.equals(SC_BA_MT)); } static String - scToBarringFacility(String sc) - { - if (sc == null) { + scToBarringFacility(String sc) { + if (sc == null) { throw new RuntimeException ("invalid call barring sc"); } @@ -383,11 +373,10 @@ public final class GsmMmiCode extends Handler implements MmiCode //***** Constructor - GsmMmiCode (GSMPhone phone) - { + GsmMmiCode (GSMPhone phone) { // The telephony unit-test cases may create GsmMmiCode's // in secondary threads - super(phone.h.getLooper()); + super(phone.getHandler().getLooper()); this.phone = phone; this.context = phone.getContext(); } @@ -395,21 +384,18 @@ public final class GsmMmiCode extends Handler implements MmiCode //***** MmiCode implementation public State - getState() - { + getState() { return state; } public CharSequence - getMessage() - { + getMessage() { return message; } // inherited javadoc suffices public void - cancel() - { + cancel() { // Complete or failed cannot be cancelled if (state == State.COMPLETE || state == State.FAILED) { return; @@ -423,7 +409,7 @@ public final class GsmMmiCode extends Handler implements MmiCode * cancel it. */ phone.mCM.cancelPendingUssd(obtainMessage(EVENT_USSD_CANCEL_COMPLETE, this)); - + /* * Don't call phone.onMMIDone here; wait for CANCEL_COMPLETE notice * from RIL. @@ -436,7 +422,6 @@ public final class GsmMmiCode extends Handler implements MmiCode phone.onMMIDone (this); } - } public boolean isCancelable() { @@ -445,20 +430,17 @@ public final class GsmMmiCode extends Handler implements MmiCode } //***** Instance Methods - /** Does this dial string contain a structured or unstructured MMI code? */ boolean - isMMI() - { + isMMI() { return poundString != null; } /* Is this a 1 or 2 digit "short code" as defined in TS 22.030 sec 6.5.3.2? */ boolean - isShortCode() - { - return poundString == null + isShortCode() { + return poundString == null && dialingNumber != null && dialingNumber.length() <= 2; } @@ -479,7 +461,7 @@ public final class GsmMmiCode extends Handler implements MmiCode * for treating "0" and "00" as call setup strings. */ || dialString.equals("0") - || dialString.equals("00")))); + || dialString.equals("00")))); } /** * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related @@ -489,17 +471,16 @@ public final class GsmMmiCode extends Handler implements MmiCode || sc.equals(SC_PUK) || sc.equals(SC_PUK2)); } - /** + /** * *See TS 22.030 Annex B - * In temporary mode, to suppress CLIR for a single call, enter: + * In temporary mode, to suppress CLIR for a single call, enter: * " * 31 # SEND " - * In temporary mode, to invoke CLIR for a single call enter: + * In temporary mode, to invoke CLIR for a single call enter: * " # 31 # SEND " */ - - boolean - isTemporaryModeCLIR() - { + + boolean + isTemporaryModeCLIR() { return sc != null && sc.equals(SC_CLIR) && dialingNumber != null && (isActivate() || isDeactivate()); } @@ -509,50 +490,43 @@ public final class GsmMmiCode extends Handler implements MmiCode * See also isTemporaryModeCLIR() */ int - getCLIRMode() - { + getCLIRMode() { if (sc != null && sc.equals(SC_CLIR)) { if (isActivate()) { return CommandsInterface.CLIR_SUPPRESSION; } else if (isDeactivate()) { - return CommandsInterface.CLIR_INVOCATION; + return CommandsInterface.CLIR_INVOCATION; } } - + return CommandsInterface.CLIR_DEFAULT; } - - boolean isActivate() - { + + boolean isActivate() { return action != null && action.equals(ACTION_ACTIVATE); } - boolean isDeactivate() - { + boolean isDeactivate() { return action != null && action.equals(ACTION_DEACTIVATE); } - - boolean isInterrogate() - { + + boolean isInterrogate() { return action != null && action.equals(ACTION_INTERROGATE); } - boolean isRegister() - { + boolean isRegister() { return action != null && action.equals(ACTION_REGISTER); } - boolean isErasure() - { + boolean isErasure() { return action != null && action.equals(ACTION_ERASURE); } - /** + /** * Returns true if this is a USSD code that's been submitted to the * network...eg, after processCode() is called */ - public boolean isPendingUSSD() - { + public boolean isPendingUSSD() { return isPendingUSSD; } @@ -562,8 +536,7 @@ public final class GsmMmiCode extends Handler implements MmiCode /** Process a MMI code or short code...anything that isn't a dialing number */ void - processCode () - { + processCode () { try { if (isShortCode()) { Log.d(LOG_TAG, "isShortCode"); @@ -573,7 +546,7 @@ public final class GsmMmiCode extends Handler implements MmiCode // We should have no dialing numbers here throw new RuntimeException ("Invalid or Unsupported MMI Code"); } else if (sc != null && sc.equals(SC_CLIP)) { - Log.d(LOG_TAG, "is CLIP"); + Log.d(LOG_TAG, "is CLIP"); if (isInterrogate()) { phone.mCM.queryCLIP( obtainMessage(EVENT_QUERY_COMPLETE, this)); @@ -581,7 +554,7 @@ public final class GsmMmiCode extends Handler implements MmiCode throw new RuntimeException ("Invalid or Unsupported MMI Code"); } } else if (sc != null && sc.equals(SC_CLIR)) { - Log.d(LOG_TAG, "is CLIR"); + Log.d(LOG_TAG, "is CLIR"); if (isActivate()) { phone.mCM.setCLIR(CommandsInterface.CLIR_INVOCATION, obtainMessage(EVENT_SET_COMPLETE, this)); @@ -688,13 +661,13 @@ public final class GsmMmiCode extends Handler implements MmiCode // sia = basic service group int serviceClass = siToServiceClass(sia); - if (isActivate() || isDeactivate()) { + if (isActivate() || isDeactivate()) { phone.mCM.setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); - } else if (isInterrogate()) { + } else if (isInterrogate()) { phone.mCM.queryCallWaiting(serviceClass, obtainMessage(EVENT_QUERY_COMPLETE, this)); - } else { + } else { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } } else if (isPinCommand()) { @@ -718,16 +691,16 @@ public final class GsmMmiCode extends Handler implements MmiCode } else { // pre-checks OK if (sc.equals(SC_PIN)) { - phone.mCM.changeSimPin(oldPinOrPuk, newPin, + phone.mCM.changeIccPin(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (sc.equals(SC_PIN2)) { - phone.mCM.changeSimPin2(oldPinOrPuk, newPin, + phone.mCM.changeIccPin2(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (sc.equals(SC_PUK)) { - phone.mCM.supplySimPuk(oldPinOrPuk, newPin, + phone.mCM.supplyIccPuk(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (sc.equals(SC_PUK2)) { - phone.mCM.supplySimPuk2(oldPinOrPuk, newPin, + phone.mCM.supplyIccPuk2(oldPinOrPuk, newPin, obtainMessage(EVENT_SET_COMPLETE, this)); } } @@ -743,7 +716,7 @@ public final class GsmMmiCode extends Handler implements MmiCode state = State.FAILED; message = context.getText(com.android.internal.R.string.mmiError); phone.onMMIDone(this); - } + } } private void handlePasswordError(int res) { @@ -755,8 +728,8 @@ public final class GsmMmiCode extends Handler implements MmiCode phone.onMMIDone(this); } - /** - * Called from GSMPhone + /** + * Called from GSMPhone * * An unsolicited USSD NOTIFY or REQUEST has come in matching * up with this pending USSD request @@ -765,8 +738,7 @@ public final class GsmMmiCode extends Handler implements MmiCode * active (ie, the network expects user input). */ void - onUssdFinished(String ussdMessage, boolean isUssdRequest) - { + onUssdFinished(String ussdMessage, boolean isUssdRequest) { if (state == State.PENDING) { if (ussdMessage == null) { message = context.getText(com.android.internal.R.string.mmiComplete); @@ -783,15 +755,14 @@ public final class GsmMmiCode extends Handler implements MmiCode } } - /** - * Called from GSMPhone + /** + * Called from GSMPhone * * The radio has reset, and this is still pending */ void - onUssdFinishedError() - { + onUssdFinishedError() { if (state == State.PENDING) { state = State.FAILED; message = context.getText(com.android.internal.R.string.mmiError); @@ -808,15 +779,14 @@ public final class GsmMmiCode extends Handler implements MmiCode // response does not complete this MMI code...we wait for // an unsolicited USSD "Notify" or "Request". // The matching up of this is doene in GSMPhone. - - phone.mCM.sendUSSD(ussdMessage, + + phone.mCM.sendUSSD(ussdMessage, obtainMessage(EVENT_USSD_COMPLETE, this)); } /** Called from GSMPhone.handleMessage; not a Handler subclass */ public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { @@ -865,13 +835,13 @@ public final class GsmMmiCode extends Handler implements MmiCode com.android.internal.R.string.mmiError); phone.onMMIDone(this); - } + } // Note that unlike most everything else, the USSD complete // response does not complete this MMI code...we wait for // an unsolicited USSD "Notify" or "Request". // The matching up of this is done in GSMPhone. - + break; case EVENT_USSD_CANCEL_COMPLETE: @@ -976,8 +946,7 @@ public final class GsmMmiCode extends Handler implements MmiCode } private void - onGetClirComplete(AsyncResult ar) - { + onGetClirComplete(AsyncResult ar) { StringBuilder sb = new StringBuilder(getScString()); sb.append("\n"); @@ -996,35 +965,35 @@ public final class GsmMmiCode extends Handler implements MmiCode com.android.internal.R.string.serviceNotProvisioned)); state = State.COMPLETE; break; - + case 1: // CLIR provisioned in permanent mode sb.append(context.getText( com.android.internal.R.string.CLIRPermanent)); state = State.COMPLETE; break; - case 2: // unknown (e.g. no network, etc.) + case 2: // unknown (e.g. no network, etc.) sb.append(context.getText( com.android.internal.R.string.mmiError)); state = State.FAILED; break; - case 3: // CLIR temporary mode presentation restricted + case 3: // CLIR temporary mode presentation restricted // the 'n' parameter from TS 27.007 7.7 switch (clirArgs[0]) { default: case 0: // Default sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOn)); + com.android.internal.R.string.CLIRDefaultOnNextCallOn)); break; case 1: // CLIR invocation sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOn)); + com.android.internal.R.string.CLIRDefaultOnNextCallOn)); break; case 2: // CLIR suppression sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOff)); + com.android.internal.R.string.CLIRDefaultOnNextCallOff)); break; } state = State.COMPLETE; @@ -1036,21 +1005,21 @@ public final class GsmMmiCode extends Handler implements MmiCode default: case 0: // Default sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOff)); + com.android.internal.R.string.CLIRDefaultOffNextCallOff)); break; case 1: // CLIR invocation sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOn)); + com.android.internal.R.string.CLIRDefaultOffNextCallOn)); break; case 2: // CLIR suppression sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOff)); + com.android.internal.R.string.CLIRDefaultOffNextCallOff)); break; } state = State.COMPLETE; break; - } + } } message = sb; @@ -1059,23 +1028,29 @@ public final class GsmMmiCode extends Handler implements MmiCode /** * @param serviceClass 1 bit of the service class bit vectory - * @return String to be used for call forward query MMI response text. + * @return String to be used for call forward query MMI response text. * Returns null if unrecognized */ private CharSequence - serviceClassToCFString (int serviceClass) - { + serviceClassToCFString (int serviceClass) { switch (serviceClass) { - case SERVICE_CLASS_VOICE: return context.getText(com.android.internal.R.string.serviceClassVoice); - case SERVICE_CLASS_DATA: return context.getText(com.android.internal.R.string.serviceClassData); - case SERVICE_CLASS_FAX: return context.getText(com.android.internal.R.string.serviceClassFAX); - case SERVICE_CLASS_SMS: return context.getText(com.android.internal.R.string.serviceClassSMS); - case SERVICE_CLASS_DATA_SYNC: return context.getText(com.android.internal.R.string.serviceClassDataSync); - case SERVICE_CLASS_DATA_ASYNC: return context.getText(com.android.internal.R.string.serviceClassDataAsync); - case SERVICE_CLASS_PACKET: return context.getText(com.android.internal.R.string.serviceClassPacket); - case SERVICE_CLASS_PAD: return context.getText(com.android.internal.R.string.serviceClassPAD); - + case SERVICE_CLASS_VOICE: + return context.getText(com.android.internal.R.string.serviceClassVoice); + case SERVICE_CLASS_DATA: + return context.getText(com.android.internal.R.string.serviceClassData); + case SERVICE_CLASS_FAX: + return context.getText(com.android.internal.R.string.serviceClassFAX); + case SERVICE_CLASS_SMS: + return context.getText(com.android.internal.R.string.serviceClassSMS); + case SERVICE_CLASS_DATA_SYNC: + return context.getText(com.android.internal.R.string.serviceClassDataSync); + case SERVICE_CLASS_DATA_ASYNC: + return context.getText(com.android.internal.R.string.serviceClassDataAsync); + case SERVICE_CLASS_PACKET: + return context.getText(com.android.internal.R.string.serviceClassPacket); + case SERVICE_CLASS_PAD: + return context.getText(com.android.internal.R.string.serviceClassPAD); default: return null; } @@ -1084,8 +1059,7 @@ public final class GsmMmiCode extends Handler implements MmiCode /** one CallForwardInfo + serviceClassMask -> one line of text */ private CharSequence - makeCFQueryResultMessage(CallForwardInfo info, int serviceClassMask) - { + makeCFQueryResultMessage(CallForwardInfo info, int serviceClassMask) { CharSequence template; String sources[] = {"{0}", "{1}", "{2}"}; CharSequence destinations[] = new CharSequence[3]; @@ -1094,7 +1068,7 @@ public final class GsmMmiCode extends Handler implements MmiCode // CF_REASON_NO_REPLY also has a time value associated with // it. All others don't. - needTimeTemplate = + needTimeTemplate = (info.reason == CommandsInterface.CF_REASON_NO_REPLY); if (info.status == 1) { @@ -1122,8 +1096,8 @@ public final class GsmMmiCode extends Handler implements MmiCode } // In the template (from strings.xmls) - // {0} is one of "bearerServiceCode*" - // {1} is dialing number + // {0} is one of "bearerServiceCode*" + // {1} is dialing number // {2} is time in seconds destinations[0] = serviceClassToCFString(info.serviceClass & serviceClassMask); @@ -1142,8 +1116,7 @@ public final class GsmMmiCode extends Handler implements MmiCode private void - onQueryCfComplete(AsyncResult ar) - { + onQueryCfComplete(AsyncResult ar) { StringBuilder sb = new StringBuilder(getScString()); sb.append("\n"); @@ -1152,7 +1125,7 @@ public final class GsmMmiCode extends Handler implements MmiCode sb.append(context.getText(com.android.internal.R.string.mmiError)); } else { CallForwardInfo infos[]; - + infos = (CallForwardInfo[]) ar.result; if (infos.length == 0) { @@ -1166,18 +1139,18 @@ public final class GsmMmiCode extends Handler implements MmiCode SpannableStringBuilder tb = new SpannableStringBuilder(); // Each bit in the service class gets its own result line - // The service classes may be split up over multiple + // The service classes may be split up over multiple // CallForwardInfos. So, for each service classs, find out // which CallForwardInfo represents it and then build // the response text based on that - for (int serviceClassMask = 1 + for (int serviceClassMask = 1 ; serviceClassMask <= SERVICE_CLASS_MAX - ; serviceClassMask <<= 1 + ; serviceClassMask <<= 1 ) { for (int i = 0, s = infos.length; i < s ; i++) { if ((serviceClassMask & infos[i].serviceClass) != 0) { - tb.append(makeCFQueryResultMessage(infos[i], + tb.append(makeCFQueryResultMessage(infos[i], serviceClassMask)); tb.append("\n"); } @@ -1191,12 +1164,11 @@ public final class GsmMmiCode extends Handler implements MmiCode message = sb; phone.onMMIDone(this); - + } private void - onQueryComplete(AsyncResult ar) - { + onQueryComplete(AsyncResult ar) { StringBuilder sb = new StringBuilder(getScString()); sb.append("\n"); @@ -1230,15 +1202,15 @@ public final class GsmMmiCode extends Handler implements MmiCode message = sb; phone.onMMIDone(this); } - + private CharSequence - createQueryCallWaitingResultMessage(int serviceClass) - { - StringBuilder sb = new StringBuilder(context.getText(com.android.internal.R.string.serviceEnabledFor)); + createQueryCallWaitingResultMessage(int serviceClass) { + StringBuilder sb = + new StringBuilder(context.getText(com.android.internal.R.string.serviceEnabledFor)); - for (int classMask = 1 + for (int classMask = 1 ; classMask <= SERVICE_CLASS_MAX - ; classMask <<= 1 + ; classMask <<= 1 ) { if ((classMask & serviceClass) != 0) { sb.append("\n"); @@ -1267,8 +1239,8 @@ public final class GsmMmiCode extends Handler implements MmiCode /*** * TODO: It would be nice to have a method here that can take in a dialstring and * figure out if there is an MMI code embedded within it. This code would replace - * some of the string parsing functionality in the Phone App's - * SpecialCharSequenceMgr class. + * some of the string parsing functionality in the Phone App's + * SpecialCharSequenceMgr class. */ } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..3e73cafda52a784e75efa7739783517bd6818298 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -0,0 +1,379 @@ +/* + * 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.app.Activity; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; +import android.content.Intent; +import android.os.AsyncResult; +import android.os.Message; +import android.telephony.ServiceState; +import android.util.Config; +import android.util.Log; + +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.SMSDispatcher; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; + +import java.util.ArrayList; +import java.util.HashMap; + + +final class GsmSMSDispatcher extends SMSDispatcher { + private static final String TAG = "GSM"; + + GsmSMSDispatcher(GSMPhone phone) { + super(phone); + } + + /** + * Called when a status report is received. This should correspond to + * a previously successful SEND. + * + * @param ar AsyncResult passed into the message handler. ar.result should + * be a String representing the status report PDU, as ASCII hex. + */ + protected void handleStatusReport(AsyncResult ar) { + String pduString = (String) ar.result; + SmsMessage sms = SmsMessage.newFromCDS(pduString); + + if (sms != null) { + int messageRef = sms.messageRef; + for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { + SmsTracker tracker = deliveryPendingList.get(i); + if (tracker.mMessageRef == messageRef) { + // Found it. Remove from list and broadcast. + deliveryPendingList.remove(i); + PendingIntent intent = tracker.mDeliveryIntent; + Intent fillIn = new Intent(); + fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString)); + try { + intent.send(mContext, Activity.RESULT_OK, fillIn); + } catch (CanceledException ex) {} + + // Only expect to see one tracker matching this messageref + break; + } + } + } + + if (mCm != null) { + mCm.acknowledgeLastIncomingSMS(true, null); + } + } + + + /** + * Dispatches an incoming SMS messages. + * + * @param sms the incoming message from the phone + */ + protected void dispatchMessage(SmsMessageBase smsb) { + + // If sms is null, means there was a parsing error. + // TODO: Should NAK this. + if (smsb == null) { + return; + } + SmsMessage sms = (SmsMessage) smsb; + boolean handled = false; + + // Special case the message waiting indicator messages + if (sms.isMWISetMessage()) { + ((GSMPhone) mPhone).updateMessageWaitingIndicator(true); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator set SMS shouldStore=" + + !handled); + } + } else if (sms.isMWIClearMessage()) { + ((GSMPhone) mPhone).updateMessageWaitingIndicator(false); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator clear SMS shouldStore=" + + !handled); + } + } + + if (handled) { + return; + } + + // Parse the headers to see if this is partial, or port addressed + int referenceNumber = -1; + int count = 0; + int sequence = 0; + int destPort = -1; + + SmsHeader header = sms.getUserDataHeader(); + if (header != null) { + for (SmsHeader.Element element : header.getElements()) { + try { + switch (element.getID()) { + case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = data[0] & 0xff; + count = data[1] & 0xff; + sequence = data[2] & 0xff; + + // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence + // is zero, or sequence > count, ignore the entire element + if (count == 0 || sequence == 0 || sequence > count) { + referenceNumber = -1; + } + break; + } + + case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); + count = data[2] & 0xff; + sequence = data[3] & 0xff; + + // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence + // is zero, or sequence > count, ignore the entire element + if (count == 0 || sequence == 0 || sequence > count) { + referenceNumber = -1; + } + break; + } + + case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { + byte[] data = element.getData(); + + destPort = (data[0] & 0xff) << 8; + destPort |= (data[1] & 0xff); + + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + Log.e(TAG, "Bad element in header", e); + return; // TODO: NACK the message or something, don't just discard. + } + } + } + + if (referenceNumber == -1) { + // notify everyone of the message if it isn't partial + byte[][] pdus = new byte[1][]; + pdus[0] = sms.getPdu(); + + if (destPort != -1) { + if (destPort == SmsHeader.PORT_WAP_PUSH) { + mWapPush.dispatchWapPdu(sms.getUserData()); + } + // The message was sent to a port, so concoct a URI for it + dispatchPortAddressedPdus(pdus, destPort); + } else { + // It's a normal message, dispatch it + dispatchPdus(pdus); + } + } else { + // Process the message part + processMessagePart(sms, referenceNumber, sequence, count, destPort); + } + } + + /** {@inheritDoc} */ + protected void sendMultipartText(String destinationAddress, String scAddress, + ArrayList parts, ArrayList sentIntents, + ArrayList deliveryIntents) { + int ref = ++sConcatenatedRef & 0xff; + + for (int i = 0, count = parts.size(); i < count; i++) { + // build SmsHeader + byte[] data = new byte[3]; + data[0] = (byte) ref; // reference #, unique per message + data[1] = (byte) count; // total part count + data[2] = (byte) (i + 1); // 1-based sequence + SmsHeader header = new SmsHeader(); + header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, header.toByteArray()); + + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + } + + /** + * Send a multi-part text based SMS which already passed SMS control check. + * + * It is the working function for sendMultipartText(). + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an ArrayList of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * @param deliveryIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + */ + private void sendMultipartTextWithPermit(String destinationAddress, + String scAddress, ArrayList parts, + ArrayList sentIntents, + ArrayList deliveryIntents) { + + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + + // check if in service + int ss = mPhone.getServiceState().getState(); + if (ss != ServiceState.STATE_IN_SERVICE) { + for (int i = 0, count = parts.size(); i < count; i++) { + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + SmsTracker tracker = SmsTrackerFactory(null, sentIntent, null); + handleNotInService(ss, tracker); + } + return; + } + + int ref = ++sConcatenatedRef & 0xff; + + for (int i = 0, count = parts.size(); i < count; i++) { + // build SmsHeader + byte[] data = new byte[3]; + data[0] = (byte) ref; // reference #, unique per message + data[1] = (byte) count; // total part count + data[2] = (byte) (i + 1); // 1-based sequence + SmsHeader header = new SmsHeader(); + header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, header.toByteArray()); + + HashMap map = new HashMap(); + map.put("smsc", pdus.encodedScAddress); + map.put("pdu", pdus.encodedMessage); + + SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent); + sendSms(tracker); + } + } + + /** {@inheritDoc} */ + protected void sendSms(SmsTracker tracker) { + HashMap map = tracker.mData; + + byte smsc[] = (byte[]) map.get("smsc"); + byte pdu[] = (byte[]) map.get("pdu"); + + Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); + mCm.sendSMS(IccUtils.bytesToHexString(smsc), + IccUtils.bytesToHexString(pdu), reply); + } + + /** + * Send the multi-part SMS based on multipart Sms tracker + * + * @param tracker holds the multipart Sms tracker ready to be sent + */ + protected void sendMultipartSms (SmsTracker tracker) { + ArrayList parts; + ArrayList sentIntents; + ArrayList deliveryIntents; + + HashMap map = tracker.mData; + + String destinationAddress = (String) map.get("destination"); + String scAddress = (String) map.get("scaddress"); + + parts = (ArrayList) map.get("parts"); + sentIntents = (ArrayList) map.get("sentIntents"); + deliveryIntents = (ArrayList) map.get("deliveryIntents"); + + sendMultipartTextWithPermit(destinationAddress, + scAddress, parts, sentIntents, deliveryIntents); + + } + + /** {@inheritDoc} */ + protected void acknowledgeLastIncomingSms(boolean success, Message response){ + // FIXME unit test leaves cm == null. this should change + if (mCm != null) { + mCm.acknowledgeLastIncomingSMS(success, response); + } + } + + /** {@inheritDoc} */ + protected void activateCellBroadcastSms(int activate, Message response) { + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + + /** {@inheritDoc} */ + protected void getCellBroadcastSmsConfig(Message response){ + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + + /** {@inheritDoc} */ + protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + +} + diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java similarity index 87% rename from telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java rename to telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index e336d7d0e7f8d8e9928970fc57e18b169b6563e6..9ab1002d646f6938ba302b96d6cc26439ff50d35 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -16,19 +16,7 @@ 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_ISO_COUNTRY; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC; - -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.DataConnectionTracker.State; - import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; @@ -49,13 +37,32 @@ import android.provider.Checkin; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.provider.Telephony.Intents; -import android.telephony.gsm.GsmCellLocation; import android.telephony.ServiceState; +import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import android.util.Config; +import android.util.EventLog; import android.util.Log; import android.util.TimeUtils; -import android.util.EventLog; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.TelephonyEventLog; +import com.android.internal.telephony.TelephonyIntents; + +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA; +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; import java.util.Arrays; import java.util.Calendar; @@ -65,30 +72,9 @@ import java.util.TimeZone; /** * {@hide} */ -final class ServiceStateTracker extends Handler -{ - /** - * The access technology currently in use: - * 0 = unknown - * 1 = GPRS only - * 2 = EDGE - * 3 = UMTS - */ - static final int DATA_ACCESS_UNKNOWN = 0; - static final int DATA_ACCESS_GPRS = 1; - static final int DATA_ACCESS_EDGE = 2; - static final int DATA_ACCESS_UMTS = 3; - - static final int MAX_NUM_DATA_STATE_READS = 15; - static final int DATA_STATE_POLL_SLEEP_MS = 100; - +final class GsmServiceStateTracker extends ServiceStateTracker { //***** Instance Variables - GSMPhone phone; - CommandsInterface cm; - - ServiceState ss; - ServiceState newSS; GsmCellLocation cellLoc; GsmCellLocation newCellLoc; int mPreferredNetworkType; @@ -97,18 +83,6 @@ final class ServiceStateTracker extends Handler int rssi = 99; // signal strength 0-31, 99=unknown // That's "received signal strength indication" fyi - int[] pollingContext; // Used as a unique identifier to - // track requests associated with a poll - // and ignore stale responses. - // The value is a count-down of expected responses - // in this pollingContext - - boolean mDesiredPowerState; - - boolean dontPollSignalStrength = false; // Default is to poll strength - // If we're getting unsolicited signal strength updates from the radio, - // set value to true and don't bother polling any more - private int gprsState = ServiceState.STATE_OUT_OF_SERVICE; private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE; @@ -120,14 +94,10 @@ final class ServiceStateTracker extends Handler /* gsm roaming status solely based on TS 27.007 7.2 CREG */ private boolean mGsmRoaming = false; - private RegistrantList networkAttachedRegistrants = new RegistrantList(); private RegistrantList gprsAttachedRegistrants = new RegistrantList(); private RegistrantList gprsDetachedRegistrants = new RegistrantList(); - private RegistrantList roamingOnRegistrants = new RegistrantList(); - private RegistrantList roamingOffRegistrants = new RegistrantList(); private RegistrantList psRestrictEnabledRegistrants = new RegistrantList(); private RegistrantList psRestrictDisabledRegistrants = new RegistrantList(); - // Sometimes we get the NITZ time before we know what country we are in. // Keep the time zone information from the NITZ string so we can fix @@ -137,6 +107,7 @@ final class ServiceStateTracker extends Handler private boolean mZoneDst; private long mZoneTime; private boolean mGotCountryCode = false; + private ContentResolver cr; String mSavedTimeZone; long mSavedTime; @@ -170,13 +141,10 @@ final class ServiceStateTracker extends Handler static final boolean DBG = true; static final String LOG_TAG = "GSM"; - // 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; - // restricted state type + // notification type static final int PS_ENABLED = 1001; // Access Control blocks data service static final int PS_DISABLED = 1002; // Access Control enables data service static final int CS_ENABLED = 1003; // Access Control blocks all voice/sms service @@ -187,72 +155,21 @@ final class ServiceStateTracker extends Handler // notification id static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted - - //***** Events - static final int EVENT_RADIO_STATE_CHANGED = 1; - static final int EVENT_NETWORK_STATE_CHANGED = 2; - static final int EVENT_GET_SIGNAL_STRENGTH = 3; - static final int EVENT_POLL_STATE_REGISTRATION = 4; - static final int EVENT_POLL_STATE_GPRS = 5; - static final int EVENT_POLL_STATE_OPERATOR = 6; - static final int EVENT_POLL_SIGNAL_STRENGTH = 10; - static final int EVENT_NITZ_TIME = 11; - static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12; - static final int EVENT_RADIO_AVAILABLE = 13; - static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14; - static final int EVENT_GET_LOC_DONE = 15; - static final int EVENT_SIM_RECORDS_LOADED = 16; - static final int EVENT_SIM_READY = 17; - static final int EVENT_LOCATION_UPDATES_ENABLED = 18; - 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; - static final int EVENT_RESTRICTED_STATE_CHANGED = 23; - - //***** Time Zones - - private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; - - // List of ISO codes for countries that can have an offset of GMT+0 - // when not in daylight savings time. This ignores some small places - // such as the Canary Islands (Spain) and Danmarkshavn (Denmark). - // The list must be sorted by code. - private static final String[] GMT_COUNTRY_CODES = { - "bf", // Burkina Faso - "ci", // Cote d'Ivoire - "eh", // Western Sahara - "fo", // Faroe Islands, Denmark - "gh", // Ghana - "gm", // Gambia - "gn", // Guinea - "gw", // Guinea Bissau - "ie", // Ireland - "lr", // Liberia - "is", // Iceland - "ma", // Morocco - "ml", // Mali - "mr", // Mauritania - "pt", // Portugal - "sl", // Sierra Leone - "sn", // Senegal - "st", // Sao Tome and Principe - "tg", // Togo - "uk", // U.K - }; private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { - Log.i("ServiceStateTracker", "Auto time state changed"); + Log.i("GsmServiceStateTracker", "Auto time state changed"); revertToNitz(); } }; - + + //***** Constructors - ServiceStateTracker(GSMPhone phone) - { + public GsmServiceStateTracker(GSMPhone phone) { + super(); + this.phone = phone; cm = phone.mCM; ss = new ServiceState(); @@ -265,13 +182,13 @@ final class ServiceStateTracker extends Handler (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); - cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null); cm.setOnNITZTime(this, EVENT_NITZ_TIME, null); cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); - cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); + cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); cm.registerForSIMReady(this, EVENT_SIM_READY, null); // system setting property AIRPLANE_MODE_ON is set in Settings. @@ -280,7 +197,7 @@ final class ServiceStateTracker extends Handler Settings.System.AIRPLANE_MODE_ON, 0); mDesiredPowerState = ! (airplaneMode > 0); - ContentResolver cr = phone.getContext().getContentResolver(); + cr = phone.getContext().getContentResolver(); cr.registerContentObserver( Settings.System.getUriFor(Settings.System.AUTO_TIME), true, mAutoTimeObserver); @@ -288,6 +205,24 @@ final class ServiceStateTracker extends Handler mNeedToRegForSimLoaded = true; } + public void dispose() { + //Unregister for all events + cm.unregisterForAvailable(this); + cm.unregisterForRadioStateChanged(this); + cm.unregisterForNetworkStateChanged(this); + cm.unregisterForSIMReady(this); + + phone.mSIMRecords.unregisterForRecordsLoaded(this); + cm.unSetOnSignalStrengthUpdate(this); + cm.unSetOnRestrictedStateChanged(this); + cm.unSetOnNITZTime(this); + cr.unregisterContentObserver(this.mAutoTimeObserver); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized"); + } + /** * Registration point for transition into GPRS attached. * @param h handler to notify @@ -303,7 +238,11 @@ final class ServiceStateTracker extends Handler } } - void registerForNetworkAttach(Handler h, int what, Object obj) { + /*protected*/ void unregisterForGprsAttached(Handler h) { + gprsAttachedRegistrants.remove(h); + } + + /*protected*/ void registerForNetworkAttach(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); networkAttachedRegistrants.add(r); @@ -311,6 +250,10 @@ final class ServiceStateTracker extends Handler r.notifyRegistrant(); } } + + /*protected*/ void unregisterForNetworkAttach(Handler h) { + networkAttachedRegistrants.remove(h); + } /** * Registration point for transition into GPRS detached. * @param h handler to notify @@ -326,52 +269,8 @@ final class ServiceStateTracker extends Handler } } - /** - * Registration point for combined roaming on - * combined roaming is true when roaming is true and ONS differs SPN - * - * @param h handler to notify - * @param what what code of message when delivered - * @param obj placed in Message.obj - */ - void registerForRoamingOn(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - roamingOnRegistrants.add(r); - - if (ss.getRoaming()) { - r.notifyRegistrant(); - } - } - - /** - * Registration point for combined roaming off - * combined roaming is true when roaming is true and ONS differs SPN - * - * @param h handler to notify - * @param what what code of message when delivered - * @param obj placed in Message.obj - */ - void registerForRoamingOff(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - roamingOffRegistrants.add(r); - - if (!ss.getRoaming()) { - r.notifyRegistrant(); - } - } - - /** - * Reregister network through toggle perferred network type - * This is a work aorund to deregister and register network since there is - * no ril api to set COPS=2 (deregister) only. - * - * @param onComplete is dispatched when this is complete. it will be - * an AsyncResult, and onComplete.obj.exception will be non-null - * on failure. - */ - void reRegisterNetwork(Message onComplete) { - cm.getPreferredNetworkType( - obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete)); + /*protected*/ void unregisterForGprsDetached(Handler h) { + gprsDetachedRegistrants.remove(h); } /** @@ -380,7 +279,7 @@ final class ServiceStateTracker extends Handler * @param what what code of message when delivered * @param obj placed in Message.obj */ - void registerForPsRestrictedEnabled(Handler h, int what, Object obj) { + /*protected*/ void registerForPsRestrictedEnabled(Handler h, int what, Object obj) { Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled "); Registrant r = new Registrant(h, what, obj); psRestrictEnabledRegistrants.add(r); @@ -389,14 +288,18 @@ final class ServiceStateTracker extends Handler r.notifyRegistrant(); } } - + + /*protected*/ void unregisterForPsRestrictedEnabled(Handler h) { + psRestrictEnabledRegistrants.remove(h); + } + /** * Registration point for transition out of packet service restricted zone. * @param h handler to notify * @param what what code of message when delivered * @param obj placed in Message.obj */ - void registerForPsRestrictedDisabled(Handler h, int what, Object obj) { + /*protected*/ void registerForPsRestrictedDisabled(Handler h, int what, Object obj) { Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled "); Registrant r = new Registrant(h, what, obj); psRestrictDisabledRegistrants.add(r); @@ -406,34 +309,21 @@ final class ServiceStateTracker extends Handler } } - //***** Called from GSMPhone - - public void - setRadioPower(boolean power) - { - mDesiredPowerState = power; - - setPowerStateToDesired(); + /*protected*/ void unregisterForPsRestrictedDisabled(Handler h) { + psRestrictDisabledRegistrants.remove(h); } + //***** Called from GSMPhone public void getLacAndCid(Message onComplete) { cm.getRegistrationState(obtainMessage( EVENT_GET_LOC_DONE, onComplete)); } - /*package*/ void enableLocationUpdates() { - cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED)); - } - - /*package*/ void disableLocationUpdates() { - cm.setLocationUpdates(false, null); - } - //***** Overridden from Handler + //***** Overridden from ServiceStateTracker public void - handleMessage (Message msg) - { + handleMessage (Message msg) { AsyncResult ar; int[] ints; String[] strings; @@ -476,8 +366,8 @@ final class ServiceStateTracker extends Handler // This callback is called when signal strength is polled // all by itself - if (!(cm.getRadioState().isOn())) { - // Polling will continue when radio turns back on + if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isCdma())) { + // Polling will continue when radio turns back on and not CDMA return; } ar = (AsyncResult) msg.obj; @@ -493,7 +383,7 @@ final class ServiceStateTracker extends Handler String states[] = (String[])ar.result; int lac = -1; int cid = -1; - if (states.length == 3) { + if (states.length >= 3) { try { if (states[1] != null && states[1].length() > 0) { lac = Integer.parseInt(states[1], 16); @@ -591,13 +481,11 @@ final class ServiceStateTracker extends Handler if (ar.exception == null) { mPreferredNetworkType = ((int[])ar.result)[0]; } else { - mPreferredNetworkType = Phone.NT_AUTO_TYPE; + mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL; } message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj); - int toggledNetworkType = - (mPreferredNetworkType == Phone.NT_AUTO_TYPE) ? - Phone.NT_GSM_TYPE : Phone.NT_AUTO_TYPE; + int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL; cm.setPreferredNetworkType(toggledNetworkType, message); break; @@ -630,42 +518,19 @@ final class ServiceStateTracker extends Handler onRestrictedStateChanged(ar); break; + default: + Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); + break; } } //***** Private Instance Methods - private void updateSpnDisplay() { - int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric()); - String spn = phone.mSIMRecords.getServiceProviderName(); - String plmn = ss.getOperatorAlphaLong(); - - if (rule != curSpnRule - || !TextUtils.equals(spn, curSpn) - || !TextUtils.equals(plmn, curPlmn)) { - boolean showSpn = - (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; - boolean showPlmn = - (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; - Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); - intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); - intent.putExtra(Intents.EXTRA_SPN, spn); - intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); - intent.putExtra(Intents.EXTRA_PLMN, plmn); - phone.getContext().sendStickyBroadcast(intent); - } - curSpnRule = rule; - curSpn = spn; - curPlmn = plmn; - } - - private void - setPowerStateToDesired() + protected void setPowerStateToDesired() { // If we want it on and it's off, turn it on if (mDesiredPowerState - && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF - ) { + && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { cm.setRadioPower(true, null); } else if (!mDesiredPowerState && cm.getRadioState().isOn()) { DataConnectionTracker dcTracker = phone.mDataConnection; @@ -674,15 +539,15 @@ final class ServiceStateTracker extends Handler EventLog.List val = new EventLog.List( dcTracker.getStateInString(), (dcTracker.getAnyDataEnabled() ? 1 : 0) ); - EventLog.writeEvent(TelephonyEventLog.EVENT_DATA_STATE_RADIO_OFF, val); + EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val); } dcTracker.cleanConnectionBeforeRadioOff(); // poll data state up to 15 times, with a 100ms delay // totaling 1.5 sec. Normal data disable action will finish in 100ms. for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { - if (dcTracker.state != State.CONNECTED - && dcTracker.state != State.DISCONNECTING) { + if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED + && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { Log.d(LOG_TAG, "Data shutdown complete."); break; } @@ -692,22 +557,37 @@ final class ServiceStateTracker extends Handler cm.setRadioPower(false, null); } // Otherwise, we're in the desired state } + + protected void updateSpnDisplay() { + int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric()); + String spn = phone.mSIMRecords.getServiceProviderName(); + String plmn = ss.getOperatorAlphaLong(); - /** Cancel a pending (if any) pollState() operation */ - private void - cancelPollState() - { - // This will effectively cancel the rest of the poll requests - pollingContext = new int[1]; + if (rule != curSpnRule + || !TextUtils.equals(spn, curSpn) + || !TextUtils.equals(plmn, curPlmn)) { + boolean showSpn = + (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; + boolean showPlmn = + (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; + Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); + intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); + intent.putExtra(Intents.EXTRA_SPN, spn); + intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); + intent.putExtra(Intents.EXTRA_PLMN, plmn); + phone.getContext().sendStickyBroadcast(intent); + } + curSpnRule = rule; + curSpn = spn; + curPlmn = plmn; } /** * Handle the result of one of the pollState()-related requests */ - private void - handlePollStateResult (int what, AsyncResult ar) - { + protected void + handlePollStateResult (int what, AsyncResult ar) { int ints[]; String states[]; @@ -749,7 +629,7 @@ final class ServiceStateTracker extends Handler if (states.length > 0) { try { regState = Integer.parseInt(states[0]); - if (states.length == 3) { + if (states.length >= 3) { if (states[1] != null && states[1].length() > 0) { lac = Integer.parseInt(states[1], 16); } @@ -820,8 +700,7 @@ final class ServiceStateTracker extends Handler } private void - setRssiDefaultValues() - { + setRssiDefaultValues() { rssi = 99; } @@ -835,8 +714,7 @@ final class ServiceStateTracker extends Handler */ private void - pollState() - { + pollState() { pollingContext = new int[1]; pollingContext[0] = 0; @@ -850,7 +728,6 @@ final class ServiceStateTracker extends Handler pollStateDone(); break; - case RADIO_OFF: newSS.setStateOff(); newCellLoc.setStateInvalid(); @@ -860,6 +737,20 @@ final class ServiceStateTracker extends Handler pollStateDone(); break; + case RUIM_NOT_READY: + case RUIM_READY: + case RUIM_LOCKED_OR_ABSENT: + case NV_NOT_READY: + case NV_READY: + Log.d(LOG_TAG, "Radio Technology Change ongoing, setting SS to off"); + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + default: // Issue all poll-related commands at once // then count down the responses, which @@ -889,6 +780,7 @@ final class ServiceStateTracker extends Handler } private static String networkTypeToString(int type) { + //Network Type from GPRS_REGISTRATION_STATE String ret = "unknown"; switch (type) { @@ -901,14 +793,16 @@ final class ServiceStateTracker extends Handler case DATA_ACCESS_UMTS: ret = "UMTS"; break; + default: + Log.e(LOG_TAG, "Wrong network type: " + Integer.toString(type)); + break; } return ret; } private void - pollStateDone() - { + pollStateDone() { if (DBG) { Log.d(LOG_TAG, "Poll ServiceState done: " + " oldSS=[" + ss + "] newSS=[" + newSS + @@ -1131,9 +1025,8 @@ final class ServiceStateTracker extends Handler } private void - queueNextSignalStrengthPoll() - { - if (dontPollSignalStrength) { + queueNextSignalStrengthPoll() { + if (dontPollSignalStrength || (cm.getRadioState().isCdma())) { // The radio is telling us about signal strength changes // we don't have to ask it return; @@ -1155,8 +1048,7 @@ final class ServiceStateTracker extends Handler * Called both for solicited and unsolicited signal stength updates */ private void - onSignalStrengthResult(AsyncResult ar) - { + onSignalStrengthResult(AsyncResult ar) { int oldRSSI = rssi; if (ar.exception != null) { @@ -1176,15 +1068,21 @@ final class ServiceStateTracker extends Handler } if (rssi != oldRSSI) { - phone.notifySignalStrength(); + try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after + // POLL_PERIOD_MILLIS) during Radio Technology Change) + phone.notifySignalStrength(); + } catch (NullPointerException ex) { + Log.d(LOG_TAG, "onSignalStrengthResult() Phone already destroyed: " + ex + + "Signal Stranth not notified"); + } } } - + /** * Set restricted state based on the OnRestrictedStateChanged notification * If any voice or packet restricted state changes, trigger a UI * notification and notify registrants when sim is ready. - * + * * @param ar an int value of RIL_RESTRICTED_STATE_* */ private void onRestrictedStateChanged(AsyncResult ar) @@ -1201,10 +1099,8 @@ final class ServiceStateTracker extends Handler newRs.setCsEmergencyRestricted( ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); - - //ignore the normal call and data restricted state before SIM READY - if (phone.getSimCard().getState() == SimCard.State.READY){ + if (phone.getIccCard().getState() == IccCard.State.READY) { newRs.setCsNormalRestricted( ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); @@ -1272,7 +1168,7 @@ final class ServiceStateTracker extends Handler setNotification(CS_NORMAL_ENABLED); } } - + rs = newRs; } Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ rs); @@ -1280,8 +1176,7 @@ final class ServiceStateTracker extends Handler /** code is registration state 0-5 from TS 27.007 7.2 */ private int - regCodeToServiceState(int code) - { + regCodeToServiceState(int code) { switch (code) { case 0: case 2: // 2 is "searching" @@ -1308,8 +1203,7 @@ final class ServiceStateTracker extends Handler * returns true if registered roam, false otherwise */ private boolean - regCodeIsRoaming (int code) - { + regCodeIsRoaming (int code) { // 5 is "in service -- roam" return 5 == code; } @@ -1323,7 +1217,7 @@ final class ServiceStateTracker extends Handler */ private boolean isRoamingBetweenOperators(boolean gsmRoaming, ServiceState s) { - String spn = SystemProperties.get(PROPERTY_SIM_OPERATOR_ALPHA, "empty"); + String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty"); String onsl = s.getOperatorAlphaLong(); String onss = s.getOperatorAlphaShort(); @@ -1331,7 +1225,7 @@ final class ServiceStateTracker extends Handler boolean equalsOnsl = onsl != null && spn.equals(onsl); boolean equalsOnss = onss != null && spn.equals(onss); - String simNumeric = SystemProperties.get(PROPERTY_SIM_OPERATOR_NUMERIC, ""); + String simNumeric = SystemProperties.get(PROPERTY_ICC_OPERATOR_NUMERIC, ""); String operatorNumeric = s.getOperatorNumeric(); boolean equalsMcc = true; @@ -1345,8 +1239,7 @@ final class ServiceStateTracker extends Handler } private static - int twoDigitsAt(String s, int offset) - { + int twoDigitsAt(String s, int offset) { int a, b; a = Character.digit(s.charAt(offset), 10); @@ -1631,7 +1524,7 @@ final class ServiceStateTracker extends Handler + (SystemClock.elapsedRealtime() - mSavedAtTime)); } } - + /** * Post a notification to NotificationManager for restricted state * @@ -1640,7 +1533,6 @@ final class ServiceStateTracker extends Handler private void setNotification(int notifyType) { Log.d(LOG_TAG, "[DSAC DEB] " + "create notification " + notifyType); - Context context = phone.getContext(); mNotification = new Notification(); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java new file mode 100644 index 0000000000000000000000000000000000000000..c163803a6ff035403a684ecca0fbefbd65ca42a4 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java @@ -0,0 +1,148 @@ +/* + * 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.telephony.PhoneNumberUtils; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsAddress; + +public class GsmSmsAddress extends SmsAddress { + + static final int OFFSET_ADDRESS_LENGTH = 0; + + static final int OFFSET_TOA = 1; + + static final int OFFSET_ADDRESS_VALUE = 2; + + /** + * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field + * + * @param offset the offset of the Address-Length byte + * @param length the length in bytes rounded up, e.g. "2 + + * (addressLength + 1) / 2" + */ + + public GsmSmsAddress(byte[] data, int offset, int length) { + origBytes = new byte[length]; + System.arraycopy(data, offset, origBytes, 0, length); + + // addressLength is the count of semi-octets, not bytes + int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff; + + int toa = origBytes[OFFSET_TOA] & 0xff; + ton = 0x7 & (toa >> 4); + + // TOA must have its high bit set + if ((toa & 0x80) != 0x80) { + throw new RuntimeException("Invalid TOA - high bit must be set"); + } + + if (isAlphanumeric()) { + // An alphanumeric address + int countSeptets = addressLength * 4 / 7; + + address = GsmAlphabet.gsm7BitPackedToString(origBytes, + OFFSET_ADDRESS_VALUE, countSeptets); + } else { + // TS 23.040 9.1.2.5 says + // that "the MS shall interpret reserved values as 'Unknown' + // but shall store them exactly as received" + + byte lastByte = origBytes[length - 1]; + + if ((addressLength & 1) == 1) { + // Make sure the final unused BCD digit is 0xf + origBytes[length - 1] |= 0xf0; + } + address = PhoneNumberUtils.calledPartyBCDToString(origBytes, + OFFSET_TOA, length - OFFSET_TOA); + + // And restore origBytes + origBytes[length - 1] = lastByte; + } + } + + public String getAddressString() { + return address; + } + + /** + * Returns true if this is an alphanumeric address + */ + public boolean isAlphanumeric() { + return ton == TON_ALPHANUMERIC; + } + + public boolean isNetworkSpecific() { + return ton == TON_NETWORK; + } + + /** + * Returns true of this is a valid CPHS voice message waiting indicator + * address + */ + public boolean isCphsVoiceMessageIndicatorAddress() { + // CPHS-style MWI message + // See CPHS 4.7 B.4.2.1 + // + // Basically: + // + // - Originating address should be 4 bytes long and alphanumeric + // - Decode will result with two chars: + // - Char 1 + // 76543210 + // ^ set/clear indicator (0 = clear) + // ^^^ type of indicator (000 = voice) + // ^^^^ must be equal to 0001 + // - Char 2: + // 76543210 + // ^ line number (0 = line 1) + // ^^^^^^^ set to 0 + // + // Remember, since the alpha address is stored in 7-bit compact form, + // the "line number" is really the top bit of the first address value + // byte + + return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4 + && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0; + } + + /** + * Returns true if this is a valid CPHS voice message waiting indicator + * address indicating a "set" of "indicator 1" of type "voice message + * waiting" + */ + public boolean isCphsVoiceMessageSet() { + // 0x11 means "set" "voice message waiting" "indicator 1" + return isCphsVoiceMessageIndicatorAddress() + && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11; + + } + + /** + * Returns true if this is a valid CPHS voice message waiting indicator + * address indicating a "clear" of "indicator 1" of type "voice message + * waiting" + */ + public boolean isCphsVoiceMessageClear() { + // 0x10 means "clear" "voice message waiting" "indicator 1" + return isCphsVoiceMessageIndicatorAddress() + && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10; + + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java index 53145fb7516c64e3901b0297fc8ca931d5848b9c..619897951e41b3c93bdc36d46d9a2dd5a57baa8d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java +++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java @@ -62,11 +62,11 @@ public final class MccTable entryForMcc(int mcc) { int index; - + MccEntry m; m = new MccEntry(mcc, null, 0); - + index = Collections.binarySearch(table, m); if (index < 0) { @@ -154,7 +154,7 @@ public final class MccTable /* * The table below is built from two resources: - * + * * 1) ITU "Mobile Network Code (MNC) for the international * identification plan for mobile terminals and mobile users" * which is available as an annex to the ITU operational bulletin @@ -167,9 +167,9 @@ public final class MccTable * * FIXME(mkf) this should be stored in a more efficient representation */ - + table.add(new MccEntry(202,"gr",2)); //Greece - table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam")); //Netherlands (Kingdom of the) + table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl")); //Netherlands (Kingdom of the) table.add(new MccEntry(206,"be",2)); //Belgium table.add(new MccEntry(208,"fr",2,"Europe/Paris","fr")); //France table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of) @@ -183,7 +183,7 @@ public final class MccTable table.add(new MccEntry(225,"va",2,"Europe/Rome","it")); //Vatican City State table.add(new MccEntry(226,"ro",2)); //Romania table.add(new MccEntry(228,"ch",2,"Europe/Zurich","en")); //Switzerland (Confederation of) - table.add(new MccEntry(230,"cz",2,"Europe/Prague")); //Czech Republic + table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs")); //Czech Republic table.add(new MccEntry(231,"sk",2)); //Slovak Republic 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 diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl index c600530a4629f7ffd4845ce967432590c26aa5d1..d88d0b721f47a84f1aa0c4f238b0cc971cd85e5f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl +++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl @@ -16,11 +16,11 @@ package com.android.internal.telephony.gsm; -/** +/** * Used to indicate that the NetworkInfo object is parcelable to aidl. * This is a simple effort to make NetworkInfo parcelable rather than * trying to make the conventional containing object (AsyncResult), - * implement parcelable. This functionality is needed for the + * implement parcelable. This functionality is needed for the * NetworkQueryService to fix 1128695 */ parcelable NetworkInfo; diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java index bebf9ba3e7687420a67efa8a43aacbe940e83c4e..04fd13e715a756c75db937318ea526f3cf499c0c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java +++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java @@ -22,8 +22,7 @@ import android.os.Parcelable; /** * {@hide} */ -public class NetworkInfo implements Parcelable -{ +public class NetworkInfo implements Parcelable { public enum State { UNKNOWN, AVAILABLE, @@ -39,34 +38,29 @@ public class NetworkInfo implements Parcelable public String - getOperatorAlphaLong() - { + getOperatorAlphaLong() { return operatorAlphaLong; } public String - getOperatorAlphaShort() - { + getOperatorAlphaShort() { return operatorAlphaShort; } public String - getOperatorNumeric() - { + getOperatorNumeric() { return operatorNumeric; } public State - getState() - { + getState() { return state; } - NetworkInfo(String operatorAlphaLong, - String operatorAlphaShort, - String operatorNumeric, - State state) - { + NetworkInfo(String operatorAlphaLong, + String operatorAlphaShort, + String operatorNumeric, + State state) { this.operatorAlphaLong = operatorAlphaLong; this.operatorAlphaShort = operatorAlphaShort; @@ -76,20 +70,18 @@ public class NetworkInfo implements Parcelable } - NetworkInfo(String operatorAlphaLong, - String operatorAlphaShort, - String operatorNumeric, - String stateString) - { - this (operatorAlphaLong, operatorAlphaShort, + public NetworkInfo(String operatorAlphaLong, + String operatorAlphaShort, + String operatorNumeric, + String stateString) { + this (operatorAlphaLong, operatorAlphaShort, operatorNumeric, rilStateToState(stateString)); } /** * See state strings defined in ril.h RIL_REQUEST_QUERY_AVAILABLE_NETWORKS */ - private static State rilStateToState(String s) - { + private static State rilStateToState(String s) { if (s.equals("unknown")) { return State.UNKNOWN; } else if (s.equals("available")) { @@ -105,29 +97,28 @@ public class NetworkInfo implements Parcelable } - public String toString() - { - return "NetworkInfo " + operatorAlphaLong - + "/" + operatorAlphaShort - + "/" + operatorNumeric + public String toString() { + return "NetworkInfo " + operatorAlphaLong + + "/" + operatorAlphaShort + + "/" + operatorNumeric + "/" + state; } - - /** + + /** * Parcelable interface implemented below. * This is a simple effort to make NetworkInfo parcelable rather than * trying to make the conventional containing object (AsyncResult), - * implement parcelable. This functionality is needed for the + * implement parcelable. This functionality is needed for the * NetworkQueryService to fix 1128695. */ - + public int describeContents() { return 0; } - /** + /** * Implement the Parcelable interface. - * Method to serialize a NetworkInfo object. + * Method to serialize a NetworkInfo object. */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(operatorAlphaLong); @@ -136,9 +127,9 @@ public class NetworkInfo implements Parcelable dest.writeSerializable(state); } - /** + /** * Implement the Parcelable interface - * Method to deserialize a NetworkInfo object, or an array thereof. + * Method to deserialize a NetworkInfo object, or an array thereof. */ public static final Creator CREATOR = new Creator() { diff --git a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java index d5d481adc92ab0e0d3f453ecfb98a2ac7e1efbb4..31cdacf5319071d1f91b0a5e177d36633c4826bd 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java +++ b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java @@ -19,10 +19,9 @@ package com.android.internal.telephony.gsm; /** * {@hide} */ -public class PDPContextState -{ +public class PDPContextState { public int cid; - public boolean active; + public int active; public String type; public String apn; public String address; diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java index 66f8b72ae128a03ffadbfbcc7b3a405d79ee977a..88acb1bfd1a23372a2dbd06ddbe6eb3955ae37f3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java @@ -17,88 +17,26 @@ 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.CommandException; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataLink; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.TelephonyEventLog; /** * {@hide} */ -public class PdpConnection extends Handler { +public class PdpConnection extends DataConnection { private static final String LOG_TAG = "GSM"; private static final boolean DBG = true; private static final boolean FAKE_FAIL = false; - public enum PdpState { - ACTIVE, /* has active pdp context */ - ACTIVATING, /* during connecting process */ - INACTIVE; /* has empty pdp context */ - - public String toString() { - switch (this) { - case ACTIVE: return "active"; - case ACTIVATING: return "setting up"; - default: return "inactive"; - } - } - - public boolean isActive() { - return this == ACTIVE; - } - - public boolean isInactive() { - return this == INACTIVE; - } - } - - public enum PdpFailCause { - NONE, - BAD_APN, - BAD_PAP_SECRET, - BARRED, - USER_AUTHENTICATION, - SERVICE_OPTION_NOT_SUPPORTED, - SERVICE_OPTION_NOT_SUBSCRIBED, - SIM_LOCKED, - RADIO_OFF, - NO_SIGNAL, - NO_DATA_PLAN, - RADIO_NOT_AVIALABLE, - SUSPENED_TEMPORARY, - RADIO_ERROR_RETRY, - UNKNOWN; - - public boolean isPermanentFail() { - return (this == RADIO_OFF); - } - - public String toString() { - switch (this) { - case NONE: return "no error"; - case BAD_APN: return "bad apn"; - case BAD_PAP_SECRET:return "bad pap secret"; - case BARRED: return "barred"; - case USER_AUTHENTICATION: return "error user autentication"; - case SERVICE_OPTION_NOT_SUPPORTED: return "data not supported"; - case SERVICE_OPTION_NOT_SUBSCRIBED: return "datt not subcribed"; - case SIM_LOCKED: return "sim locked"; - case RADIO_OFF: return "radio is off"; - case NO_SIGNAL: return "no signal"; - case NO_DATA_PLAN: return "no data plan"; - case RADIO_NOT_AVIALABLE: return "radio not available"; - case SUSPENED_TEMPORARY: return "suspend temporary"; - case RADIO_ERROR_RETRY: return "transient radio error"; - default: return "unknown data error"; - } - } - } - /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */ private static final int PDP_FAIL_RIL_BARRED = 8; private static final int PDP_FAIL_RIL_BAD_APN = 27; @@ -107,54 +45,20 @@ public class PdpConnection extends Handler { private static final int PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED = 33; private static final int PDP_FAIL_RIL_ERROR_UNSPECIFIED = 0xffff; - //***** Event codes - private static final int EVENT_SETUP_PDP_DONE = 1; - private static final int EVENT_GET_LAST_FAIL_DONE = 2; - private static final int EVENT_LINK_STATE_CHANGED = 3; - private static final int EVENT_DEACTIVATE_DONE = 4; - private static final int EVENT_FORCE_RETRY = 5; - //***** Instance Variables - private GSMPhone phone; private String pdp_name; - private PdpState state; - private Message onConnectCompleted; - private Message onDisconnect; - private int cid; - private long createTime; - private long lastFailTime; - private PdpFailCause lastFailCause; private ApnSetting apn; - private String interfaceName; - private String ipAddress; - private String gatewayAddress; - private String[] dnsServers; - - private static final String NULL_IP = "0.0.0.0"; // dataLink is only used to support pppd link - DataLink dataLink; - // receivedDisconnectReq is set when disconnect pdp link during activating - private boolean receivedDisconnectReq; + private DataLink dataLink; //***** Constructor - PdpConnection(GSMPhone phone) - { - this.phone = phone; - this.state = PdpState.INACTIVE; - onConnectCompleted = null; - onDisconnect = null; - this.cid = -1; - this.createTime = -1; - this.lastFailTime = -1; - this.lastFailCause = PdpFailCause.NONE; - this.apn = null; + PdpConnection(GSMPhone phone) { + super(phone); this.dataLink = null; - receivedDisconnectReq = false; - this.dnsServers = new String[2]; if (SystemProperties.get("ro.radio.use-ppp","no").equals("yes")) { - dataLink = new PppLink(phone.mDataConnection); + dataLink = new PppLink((GsmDataConnectionTracker) phone.mDataConnection, phone); dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null); } } @@ -171,37 +75,37 @@ public class PdpConnection extends Handler { setHttpProxy (apn.proxy, apn.port); - state = PdpState.ACTIVATING; + state = State.ACTIVATING; this.apn = apn; onConnectCompleted = onCompleted; createTime = -1; lastFailTime = -1; - lastFailCause = PdpFailCause.NONE; + lastFailCause = FailCause.NONE; receivedDisconnectReq = false; if (FAKE_FAIL) { // for debug before baseband implement error in setup PDP if (apn.apn.equalsIgnoreCase("badapn")){ - notifyFail(PdpFailCause.BAD_APN, onConnectCompleted); + notifyFail(FailCause.BAD_APN, onConnectCompleted); return; } } - phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password, - obtainMessage(EVENT_SETUP_PDP_DONE)); + phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE), null, apn.apn, apn.user, + apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); } - void disconnect(Message msg) { + protected void disconnect(Message msg) { onDisconnect = msg; - if (state == PdpState.ACTIVE) { + if (state == State.ACTIVE) { if (dataLink != null) { dataLink.disconnect(); } if (phone.mCM.getRadioState().isOn()) { - phone.mCM.deactivateDefaultPDP(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); } - } else if (state == PdpState.ACTIVATING) { + } else if (state == State.ACTIVATING) { receivedDisconnectReq = true; } else { // state == INACTIVE. Nothing to do, so notify immediately. @@ -209,20 +113,9 @@ public class PdpConnection extends Handler { } } - private void - setHttpProxy(String httpProxy, String httpPort) - { - if (httpProxy == null || httpProxy.length() == 0) { - phone.setSystemProperty("net.gprs.http-proxy", null); - return; - } - - if (httpPort == null || httpPort.length() == 0) { - httpPort = "8080"; // Default to port 8080 - } - - phone.setSystemProperty("net.gprs.http-proxy", - "http://" + httpProxy + ":" + httpPort + "/"); + public void clearSettings() { + super.clearSettings(); + apn = null; } public String toString() { @@ -231,61 +124,30 @@ public class PdpConnection extends Handler { " lastFailCause=" + lastFailCause; } - public long getConnectionTime() { - return createTime; - } - - public long getLastFailTime() { - return lastFailTime; - } - - public PdpFailCause getLastFailCause() { - return lastFailCause; - } - - public ApnSetting getApn() { - return apn; - } - - String getInterface() { - return interfaceName; - } - - String getIpAddress() { - return ipAddress; - } - - String getGatewayAddress() { - return gatewayAddress; - } - - String[] getDnsServers() { - return dnsServers; - } - - public PdpState getState() { - return state; - } - private void notifyFail(PdpFailCause cause, Message onCompleted) { + protected void notifyFail(FailCause cause, Message onCompleted) { if (onCompleted == null) return; - state = PdpState.INACTIVE; + state = State.INACTIVE; lastFailCause = cause; lastFailTime = System.currentTimeMillis(); onConnectCompleted = null; - if (DBG) log("Notify PDP fail at " + lastFailTime - + " due to " + lastFailCause); + if (DBG) { + log("Notify PDP fail at " + lastFailTime + + " due to " + lastFailCause); + } AsyncResult.forMessage(onCompleted, cause, new Exception()); onCompleted.sendToTarget(); } - private void notifySuccess(Message onCompleted) { - if (onCompleted == null) return; + protected void notifySuccess(Message onCompleted) { + if (onCompleted == null) { + return; + } - state = PdpState.ACTIVE; + state = State.ACTIVE; createTime = System.currentTimeMillis(); onConnectCompleted = null; onCompleted.arg1 = cid; @@ -296,7 +158,7 @@ public class PdpConnection extends Handler { onCompleted.sendToTarget(); } - private void notifyDisconnect(Message msg) { + protected void notifyDisconnect(Message msg) { if (DBG) log("Notify PDP disconnect"); if (msg != null) { @@ -306,22 +168,7 @@ public class PdpConnection extends Handler { clearSettings(); } - void clearSettings() { - state = PdpState.INACTIVE; - receivedDisconnectReq = false; - createTime = -1; - lastFailTime = -1; - lastFailCause = PdpFailCause.NONE; - apn = null; - onConnectCompleted = null; - interfaceName = null; - ipAddress = null; - gatewayAddress = null; - dnsServers[0] = null; - dnsServers[1] = null; - } - - private void onLinkStateChanged(DataLink.LinkState linkState) { + protected void onLinkStateChanged(DataLink.LinkState linkState) { switch (linkState) { case LINK_UP: notifySuccess(onConnectCompleted); @@ -335,151 +182,110 @@ public class PdpConnection extends Handler { } } - private PdpFailCause getFailCauseFromRequest(int rilCause) { - PdpFailCause cause; + protected FailCause getFailCauseFromRequest(int rilCause) { + FailCause cause; switch (rilCause) { case PDP_FAIL_RIL_BARRED: - cause = PdpFailCause.BARRED; + cause = FailCause.BARRED; break; case PDP_FAIL_RIL_BAD_APN: - cause = PdpFailCause.BAD_APN; + cause = FailCause.BAD_APN; break; case PDP_FAIL_RIL_USER_AUTHENTICATION: - cause = PdpFailCause.USER_AUTHENTICATION; + cause = FailCause.USER_AUTHENTICATION; break; case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUPPORTED: - cause = PdpFailCause.SERVICE_OPTION_NOT_SUPPORTED; + cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; break; case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED: - cause = PdpFailCause.SERVICE_OPTION_NOT_SUBSCRIBED; + cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; break; default: - cause = PdpFailCause.UNKNOWN; + cause = FailCause.UNKNOWN; } return cause; } - - private void log(String s) { + protected void log(String s) { Log.d(LOG_TAG, "[PdpConnection] " + s); } @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case EVENT_SETUP_PDP_DONE: - ar = (AsyncResult) msg.obj; - - if (ar.exception != null) { - Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception); - - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - if ( ar.exception instanceof CommandException && - ((CommandException) (ar.exception)).getCommandError() - == CommandException.Error.RADIO_NOT_AVAILABLE) { - notifyFail(PdpFailCause.RADIO_NOT_AVIALABLE, - onConnectCompleted); - } else { - phone.mCM.getLastPdpFailCause( - obtainMessage(EVENT_GET_LAST_FAIL_DONE)); - } - } + protected void onDeactivated(AsyncResult ar) { + notifyDisconnect((Message) ar.userObj); + if (DBG) log("PDP Connection Deactivated"); + } + + @Override + protected void onSetupConnectionCompleted(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception); + + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + if ( ar.exception instanceof CommandException && + ((CommandException) (ar.exception)).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE) { + notifyFail(FailCause.RADIO_NOT_AVAILABLE, + onConnectCompleted); } else { - if (receivedDisconnectReq) { - // 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); - cid = Integer.parseInt(response[0]); - - if (response.length > 2) { - interfaceName = response[1]; - ipAddress = response[2]; - String prefix = "net." + interfaceName + "."; - gatewayAddress = SystemProperties.get(prefix + "gw"); - dnsServers[0] = SystemProperties.get(prefix + "dns1"); - dnsServers[1] = SystemProperties.get(prefix + "dns2"); - if (DBG) { - log("interface=" + interfaceName + " ipAddress=" + ipAddress - + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] - + " DNS2=" + dnsServers[1]); - } - - if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) - && !phone.isDnsCheckDisabled()) { - // Work around a race condition where QMI does not fill in DNS: - // Deactivate PDP and let DataConnectionTracker retry. - // 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(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, - dnsServers[0]); - phone.mCM.deactivateDefaultPDP(cid, - obtainMessage(EVENT_FORCE_RETRY)); - break; - } - } - } + phone.mCM.getLastPdpFailCause( + obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + } + } + } else { + if (receivedDisconnectReq) { + // Don't bother reporting success if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + disconnect(onDisconnect); + } else { + String[] response = ((String[]) ar.result); + cid = Integer.parseInt(response[0]); + + if (response.length > 2) { + interfaceName = response[1]; + ipAddress = response[2]; + String prefix = "net." + interfaceName + "."; + gatewayAddress = SystemProperties.get(prefix + "gw"); + dnsServers[0] = SystemProperties.get(prefix + "dns1"); + dnsServers[1] = SystemProperties.get(prefix + "dns2"); + if (DBG) { + log("interface=" + interfaceName + " ipAddress=" + ipAddress + + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] + + " DNS2=" + dnsServers[1]); + } - if (dataLink != null) { - dataLink.connect(); - } else { - onLinkStateChanged(DataLink.LinkState.LINK_UP); + if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) + && !((GSMPhone) phone).isDnsCheckDisabled()) { + // Work around a race condition where QMI does not fill in DNS: + // Deactivate PDP and let DataConnectionTracker retry. + // 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(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, + dnsServers[0]); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); + return; } - - if (DBG) log("PDP setup on cid = " + cid); } } - break; - case EVENT_FORCE_RETRY: - if (receivedDisconnectReq) { - notifyDisconnect(onDisconnect); - } else { - ar = (AsyncResult) msg.obj; - notifyFail(PdpFailCause.RADIO_ERROR_RETRY, onConnectCompleted); - } - break; - case EVENT_GET_LAST_FAIL_DONE: - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - ar = (AsyncResult) msg.obj; - PdpFailCause cause = PdpFailCause.UNKNOWN; - if (ar.exception == null) { - int rilFailCause = ((int[]) (ar.result))[0]; - cause = getFailCauseFromRequest(rilFailCause); - } - notifyFail(cause, onConnectCompleted); + if (dataLink != null) { + dataLink.connect(); + } else { + onLinkStateChanged(DataLink.LinkState.LINK_UP); } - break; - case EVENT_LINK_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - DataLink.LinkState ls = (DataLink.LinkState) ar.result; - onLinkStateChanged(ls); - break; - case EVENT_DEACTIVATE_DONE: - ar = (AsyncResult) msg.obj; - notifyDisconnect((Message) ar.userObj); - break; + if (DBG) log("PDP setup on cid = " + cid); + } } } @@ -488,4 +294,8 @@ public class PdpConnection extends Handler { return Regex.IP_ADDRESS_PATTERN.matcher(apn.mmsProxy).matches(); } + + public ApnSetting getApn() { + return this.apn; + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/PppLink.java b/telephony/java/com/android/internal/telephony/gsm/PppLink.java index 43d4f1f91350d6dfd635ab286a2f99bdf908303d..96276968add19cf823988291689856e4337a58c1 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PppLink.java +++ b/telephony/java/com/android/internal/telephony/gsm/PppLink.java @@ -16,28 +16,31 @@ package com.android.internal.telephony.gsm; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.RandomAccessFile; - import android.database.Cursor; import android.os.Message; import android.os.SystemProperties; import android.os.SystemService; -import com.android.internal.telephony.gsm.DataConnectionTracker.State; -import com.android.internal.util.ArrayUtils; import android.util.Log; +import com.android.internal.telephony.DataLink; +import com.android.internal.telephony.DataConnectionTracker.State; +import com.android.internal.telephony.PhoneBase; +import com.android.internal.util.ArrayUtils; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; + /** * Represents a PPP link. - * + * * Ideally this would be managed by the RIL implementation, but * we currently have implementations where this is not the case. * * {@hide} */ -final class PppLink extends DataLink implements DataLinkInterface { +final class PppLink extends DataLink { private static final String LOG_TAG = "GSM"; static final String PATH_PPP_OPERSTATE = "/sys/class/net/ppp0/operstate"; @@ -69,11 +72,14 @@ final class PppLink extends DataLink implements DataLinkInterface { }; private final byte[] mCheckPPPBuffer = new byte[32]; + private PhoneBase phone; + int lastPppdExitCode = EXIT_OK; - PppLink(DataConnectionTracker dc) { + PppLink(GsmDataConnectionTracker dc, GSMPhone p) { super(dc); + this.phone = p; } public void connect() { @@ -131,7 +137,7 @@ final class PppLink extends DataLink implements DataLinkInterface { checkPPP(); // keep polling in case interface goes down - if (dataConnection.state != State.IDLE) { + if (dataConnection.getState() != State.IDLE) { Message poll = obtainMessage(); poll.what = EVENT_POLL_DATA_CONNECTION; sendMessageDelayed(poll, POLL_SYSFS_MILLIS); @@ -141,7 +147,7 @@ final class PppLink extends DataLink implements DataLinkInterface { } private void checkPPP() { - boolean connecting = (dataConnection.state == State.CONNECTING); + boolean connecting = (dataConnection.getState() == State.CONNECTING); try { RandomAccessFile file = new RandomAccessFile(PATH_PPP_OPERSTATE, "r"); @@ -152,10 +158,10 @@ final class PppLink extends DataLink implements DataLinkInterface { // "unknown" where one might otherwise expect "up" if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length) || ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING, - UNKNOWN_ASCII_STRING.length) - && dataConnection.state == State.CONNECTING) { + UNKNOWN_ASCII_STRING.length) + && dataConnection.getState() == State.CONNECTING) { - Log.i(LOG_TAG, + Log.i(LOG_TAG, "found ppp interface. Notifying GPRS connected"); if (mLinkChangeRegistrant != null) { @@ -163,23 +169,23 @@ final class PppLink extends DataLink implements DataLinkInterface { } connecting = false; - } else if (dataConnection.state == State.CONNECTED + } else if (dataConnection.getState() == State.CONNECTED && ArrayUtils.equals(mCheckPPPBuffer, DOWN_ASCII_STRING, - DOWN_ASCII_STRING.length)) { + DOWN_ASCII_STRING.length)) { - Log.i(LOG_TAG, + Log.i(LOG_TAG, "ppp interface went down. Reconnecting..."); if (mLinkChangeRegistrant != null) { mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN); } - } + } } catch (IOException ex) { if (! (ex instanceof FileNotFoundException)) { Log.i(LOG_TAG, "Poll ppp0 ex " + ex.toString()); } - if (dataConnection.state == State.CONNECTED && + if (dataConnection.getState() == State.CONNECTED && mLinkChangeRegistrant != null) { mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN); } @@ -206,4 +212,8 @@ final class PppLink extends DataLink implements DataLinkInterface { } } + + protected void log(String s) { + Log.d(LOG_TAG, "[PppLink] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java index 81fc657bddbe589b79b8739e1a6b3dda2ceab9e1..a08cdde481f4a20a8d3122d0ec38439924c1387f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java @@ -16,506 +16,78 @@ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; -import com.android.internal.telephony.gsm.stk.ImageDescriptor; -import android.os.*; -import android.os.AsyncResult; -import android.os.RegistrantList; -import android.os.Registrant; +import android.os.Message; import android.util.Log; -import java.util.ArrayList; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccFileHandler; /** * {@hide} */ -public final class SIMFileHandler extends Handler -{ +public final class SIMFileHandler extends IccFileHandler implements IccConstants { static final String LOG_TAG = "GSM"; - //from TS 11.11 9.1 or elsewhere - static private final int COMMAND_READ_BINARY = 0xb0; - static private final int COMMAND_UPDATE_BINARY = 0xd6; - static private final int COMMAND_READ_RECORD = 0xb2; - static private final int COMMAND_UPDATE_RECORD = 0xdc; - static private final int COMMAND_SEEK = 0xa2; - static private final int COMMAND_GET_RESPONSE = 0xc0; - - // from TS 11.11 9.2.5 - static private final int READ_RECORD_MODE_ABSOLUTE = 4; - - //***** types of files TS 11.11 9.3 - static private final int EF_TYPE_TRANSPARENT = 0; - static private final int EF_TYPE_LINEAR_FIXED = 1; - static private final int EF_TYPE_CYCLIC = 3; - - //***** types of files TS 11.11 9.3 - static private final int TYPE_RFU = 0; - static private final int TYPE_MF = 1; - static private final int TYPE_DF = 2; - static private final int TYPE_EF = 4; - - // size of GET_RESPONSE for EF - static private final int GET_RESPONSE_EF_SIZE_BYTES = 15; - - // Byte order received in response to COMMAND_GET_RESPONSE - // Refer TS 51.011 Section 9.2.1 - static private final int RESPONSE_DATA_RFU_1 = 0; - static private final int RESPONSE_DATA_RFU_2 = 1; - - static private final int RESPONSE_DATA_FILE_SIZE_1 = 2; - static private final int RESPONSE_DATA_FILE_SIZE_2 = 3; - - static private final int RESPONSE_DATA_FILE_ID_1 = 4; - static private final int RESPONSE_DATA_FILE_ID_2 = 5; - static private final int RESPONSE_DATA_FILE_TYPE = 6; - static private final int RESPONSE_DATA_RFU_3 = 7; - static private final int RESPONSE_DATA_ACCESS_CONDITION_1 = 8; - static private final int RESPONSE_DATA_ACCESS_CONDITION_2 = 9; - static private final int RESPONSE_DATA_ACCESS_CONDITION_3 = 10; - static private final int RESPONSE_DATA_FILE_STATUS = 11; - static private final int RESPONSE_DATA_LENGTH = 12; - static private final int RESPONSE_DATA_STRUCTURE = 13; - static private final int RESPONSE_DATA_RECORD_LENGTH = 14; - //***** Instance Variables - GSMPhone phone; - - //***** Events - - /** Finished retrieving size of transparent EF; start loading. */ - static private final int EVENT_GET_BINARY_SIZE_DONE = 4; - /** Finished loading contents of transparent EF; post result. */ - static private final int EVENT_READ_BINARY_DONE = 5; - /** Finished retrieving size of records for linear-fixed EF; now load. */ - static private final int EVENT_GET_RECORD_SIZE_DONE = 6; - /** Finished loading single record from a linear-fixed EF; post result. */ - static private final int EVENT_READ_RECORD_DONE = 7; - /** Finished retrieving record size; post result. */ - static private final int EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE = 8; - /** Finished retrieving image instance record; post result. */ - static private final int EVENT_READ_IMG_DONE = 9; - /** Finished retrieving icon data; post result. */ - static private final int EVENT_READ_ICON_DONE = 10; - - //***** Inner Classes - - static class LoadLinearFixedContext - { - - int efid; - int recordNum, recordSize, countRecords; - boolean loadAll; - - Message onLoaded; - - ArrayList results; - - LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) - { - this.efid = efid; - this.recordNum = recordNum; - this.onLoaded = onLoaded; - this.loadAll = false; - } - - LoadLinearFixedContext(int efid, Message onLoaded) - { - this.efid = efid; - this.recordNum = 1; - this.loadAll = true; - this.onLoaded = onLoaded; - } - - } - //***** Constructor - SIMFileHandler(GSMPhone phone) - { - this.phone = phone; + SIMFileHandler(GSMPhone phone) { + super(phone); } - //***** Public Methods - - /** - * Load a record from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) - { - Message response - = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, recordNum, onLoaded)); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load a image instance record from a SIM Linear Fixed EF-IMG - * - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - public void loadEFImgLinearFixed(int recordNum, Message onLoaded) { - Message response = obtainMessage(EVENT_READ_IMG_DONE, - new LoadLinearFixedContext(SimConstants.EF_IMG, recordNum, - onLoaded)); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, SimConstants.EF_IMG, "img", - recordNum, READ_RECORD_MODE_ABSOLUTE, - ImageDescriptor.ID_LENGTH, null, null, response); - } - - /** - * get record size for a linear fixed EF - * - * @param fileid EF id - * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[] - * int[0] is the record length int[1] is the total length of the EF - * file int[3] is the number of records in the EF file So int[0] * - * int[3] = int[1] - */ - void getEFLinearRecordSize(int fileid, Message onLoaded) - { - Message response - = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, onLoaded)); - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load all records from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is an ArrayList - * - */ - void loadEFLinearFixedAll(int fileid, Message onLoaded) - { - Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid,onLoaded)); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load a SIM Transparent EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - - void loadEFTransparent(int fileid, Message onLoaded) - { - Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, - fileid, 0, onLoaded); - - phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + public void dispose() { + super.dispose(); } - /** - * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to - * retrive STK's icon data. - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, - int length, Message onLoaded) { - Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, - onLoaded); - - phone.mCM.simIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset, - length, null, null, response); + protected void finalize() { + Log.d(LOG_TAG, "SIMFileHandler finalized"); } - /** - * Update a record in a linear fixed EF - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param data must be exactly as long as the record in the EF - * @param pin2 for CHV2 operations, otherwist must be null - * @param onComplete onComplete.obj will be an AsyncResult - * onComplete.obj.userObj will be a SimIoResult on success - */ - void updateEFLinearFixed(int fileid, int recordNum, byte[] data, - String pin2, Message onComplete) - { - phone.mCM.simIO(COMMAND_UPDATE_RECORD, fileid, null, - recordNum, READ_RECORD_MODE_ABSOLUTE, data.length, - SimUtils.bytesToHexString(data), pin2, onComplete); - } + //***** Overridden from IccFileHandler - /** - * Update a transparent EF - * @param fileid EF id - * @param data must be exactly as long as the EF - */ - void updateEFTransparent(int fileid, byte[] data, Message onComplete) - { - phone.mCM.simIO(COMMAND_UPDATE_BINARY, fileid, null, - 0, 0, data.length, - SimUtils.bytesToHexString(data), null, onComplete); + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); } - //***** Overridden from Handler - - public void handleMessage(Message msg) - { - AsyncResult ar; - SimIoResult result; - Message response = null; - String str; - LoadLinearFixedContext lc; - - SimException simException; - byte data[]; - int size; - int fileid; - int recordNum; - int recordSize[]; - - try { - switch (msg.what) { - case EVENT_READ_IMG_DONE: - ar = (AsyncResult) msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - simException = result.getException(); - if (simException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_READ_ICON_DONE: - ar = (AsyncResult) msg.obj; - response = (Message) ar.userObj; - result = (SimIoResult) ar.result; - - simException = result.getException(); - if (simException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE: - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - if (simException != null) { - sendResult(response, null, simException); - break; - } - - data = result.payload; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || - EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new SimFileTypeMismatch(); - } - - recordSize = new int[3]; - recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - recordSize[2] = recordSize[1] / recordSize[0]; - - sendResult(response, recordSize, null); - break; - case EVENT_GET_RECORD_SIZE_DONE: - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - data = result.payload; - fileid = lc.efid; - recordNum = lc.recordNum; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new SimFileTypeMismatch(); - } - - if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new SimFileTypeMismatch(); - } - - lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - lc.countRecords = size / lc.recordSize; - - if (lc.loadAll) { - lc.results = new ArrayList(lc.countRecords); - } - - phone.mCM.simIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - break; - case EVENT_GET_BINARY_SIZE_DONE: - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (SimIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - data = result.payload; - - fileid = msg.arg1; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new SimFileTypeMismatch(); - } - - if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { - throw new SimFileTypeMismatch(); - } - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - phone.mCM.simIO(COMMAND_READ_BINARY, fileid, null, - 0, 0, size, null, null, - obtainMessage(EVENT_READ_BINARY_DONE, - fileid, 0, response)); - break; - - case EVENT_READ_RECORD_DONE: - - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (SimIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - if (!lc.loadAll) { - sendResult(response, result.payload, null); - } else { - lc.results.add(result.payload); - - lc.recordNum++; - - if (lc.recordNum > lc.countRecords) { - sendResult(response, lc.results, null); - } else { - phone.mCM.simIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - } - } - - break; - - case EVENT_READ_BINARY_DONE: - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (SimIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - simException = result.getException(); - - if (simException != null) { - sendResult(response, null, simException); - break; - } - - sendResult(response, result.payload, null); - break; - - }} catch (Exception exc) { - if (response != null) { - sendResult(response, null, exc); - } else { - Log.e(LOG_TAG, "uncaught exception", exc); - } + protected String getEFPath(int efid) { + // TODO(): Make changes when USIM is supported + // TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility. + // Implement this after discussion with OEMs. + switch(efid) { + case EF_SMS: + return MF_SIM + DF_TELECOM; + + case EF_EXT6: + case EF_MWIS: + case EF_MBI: + case EF_SPN: + case EF_AD: + case EF_MBDN: + case EF_PNN: + case EF_SPDI: + case EF_SST: + case EF_CFIS: + return MF_SIM + DF_GSM; + + case EF_MAILBOX_CPHS: + case EF_VOICE_MAIL_INDICATOR_CPHS: + case EF_CFF_CPHS: + case EF_SPN_CPHS: + case EF_SPN_SHORT_CPHS: + case EF_INFO_CPHS: + return MF_SIM + DF_GSM; } + return getCommonIccEFPath(efid); } - //***** Private Methods - - private void sendResult(Message response, Object result, Throwable ex) - { - if (response == null) { - return; - } - - AsyncResult.forMessage(response, result, ex); + protected void logd(String msg) { + Log.d(LOG_TAG, "[SIMFileHandler] " + msg); + } - response.sendToTarget(); + protected void loge(String msg) { + Log.e(LOG_TAG, "[SIMFileHandler] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index 4467536212ba8f4a4f659086c4e27caf5309acd9..f9015d92dce20900a5fdb226eee45d4f96add49a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -16,26 +16,45 @@ package com.android.internal.telephony.gsm; +import android.app.ActivityManagerNative; import android.app.AlarmManager; +import android.app.IActivityManager; import android.content.Context; +import android.content.res.Configuration; 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.os.Registrant; import android.util.Log; import java.util.ArrayList; + import static com.android.internal.telephony.TelephonyProperties.*; -import com.android.internal.telephony.SimCard; + +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.AdnRecordLoader; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.gsm.SimCard; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccRecords; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.IccVmFixedException; +import com.android.internal.telephony.IccVmNotSupportedException; +import com.android.internal.telephony.PhoneProxy; + + + + + + /** * {@hide} */ -public final class SIMRecords extends Handler implements SimConstants -{ +public final class SIMRecords extends IccRecords { static final String LOG_TAG = "GSM"; private static final boolean CRASH_RIL = false; @@ -44,37 +63,19 @@ public final class SIMRecords extends Handler implements SimConstants //***** Instance Variables - GSMPhone phone; - RegistrantList recordsLoadedRegistrants = new RegistrantList(); - - int recordsToLoad; // number of pending load requests + VoiceMailConstants mVmConfig; - AdnRecordCache adnCache; - VoiceMailConstants mVmConfig; SpnOverride mSpnOverride; //***** Cached SIM State; cleared on channel close - boolean recordsRequested = false; // true if we've made requests for the sim records - String imsi; - String iccid; - String msisdn = null; // My mobile number - String msisdnTag = null; - String voiceMailNum = null; - String voiceMailTag = null; - String newVoiceMailNum = null; - String newVoiceMailTag = null; - boolean isVoiceMailFixed = false; - int countVoiceMessages = 0; boolean callForwardingEnabled; - int mncLength = 0; // 0 is used to indicate that the value - // is not initialized - int mailboxIndex = 0; // 0 is no mailbox dailing number associated + /** - * Sates only used by getSpnFsm FSM + * States only used by getSpnFsm FSM */ private Get_Spn_Fsm_State spnState; @@ -157,9 +158,8 @@ public final class SIMRecords extends Handler implements SimConstants //***** Constructor - SIMRecords(GSMPhone phone) - { - this.phone = phone; + SIMRecords(GSMPhone p) { + super(p); adnCache = new AdnRecordCache(phone); @@ -172,30 +172,35 @@ public final class SIMRecords extends Handler implements SimConstants recordsToLoad = 0; - phone.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); - phone.mCM.registerForOffOrNotAvailable( + p.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); + p.mCM.registerForOffOrNotAvailable( this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - phone.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); - phone.mCM.setOnSimRefresh(this, EVENT_SIM_REFRESH, null); + p.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); + p.mCM.setOnIccRefresh(this, EVENT_SIM_REFRESH, null); // Start off by setting empty state - onRadioOffOrNotAvailable(); + onRadioOffOrNotAvailable(); } - AdnRecordCache getAdnCache() { - return adnCache; + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForSIMReady(this); + phone.mCM.unregisterForOffOrNotAvailable( this); + phone.mCM.unSetOnIccRefresh(this); } - private void onRadioOffOrNotAvailable() - { + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SIMRecords finalized"); + } + + protected void onRadioOffOrNotAvailable() { imsi = null; msisdn = null; voiceMailNum = null; countVoiceMessages = 0; mncLength = 0; iccid = null; - spn = null; // -1 means no EF_SPN found; treat accordingly. spnDisplayCondition = -1; efMWIS = null; @@ -205,9 +210,9 @@ public final class SIMRecords extends Handler implements SimConstants adnCache.reset(); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null); // recordsRequested is set to false indicating that the SIM // read requests made so far are not valid. This is set to @@ -217,24 +222,13 @@ public final class SIMRecords extends Handler implements SimConstants //***** Public Methods - public void registerForRecordsLoaded(Handler h, int what, Object obj) - { - Registrant r = new Registrant(h, what, obj); - recordsLoadedRegistrants.add(r); - - if (recordsToLoad == 0 && recordsRequested == true) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } /** Returns null if SIM is not yet ready */ - public String getIMSI() - { + public String getIMSI() { return imsi; } - public String getMsisdnNumber() - { + public String getMsisdnNumber() { return msisdn; } @@ -272,20 +266,10 @@ public final class SIMRecords extends Handler implements SimConstants return msisdnTag; } - public String getVoiceMailNumber() - { + public String getVoiceMailNumber() { return voiceMailNum; } - /** - * Return Service Provider Name stored in SIM - * @return null if SIM is not yet ready - */ - String getServiceProviderName() - { - return spn; - } - /** * Set voice mail number to SIM record * @@ -293,7 +277,7 @@ public final class SIMRecords extends Handler implements SimConstants * EF_MAILBOX_CPHS (CPHS 4.2) * * If EF_MBDN is available, store the voice mail number to EF_MBDN - * + * * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS * * So the voice mail number will be stored in both EFs if both are available @@ -314,7 +298,7 @@ public final class SIMRecords extends Handler implements SimConstants Message onComplete) { if (isVoiceMailFixed) { AsyncResult.forMessage((onComplete)).exception = - new SimVmFixedException("Voicemail number is fixed by operator"); + new IccVmFixedException("Voicemail number is fixed by operator"); onComplete.sendToTarget(); return; } @@ -336,9 +320,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 SimVmNotSupportedException("Update SIM voice mailbox error"); + new IccVmNotSupportedException("Update SIM voice mailbox error"); onComplete.sendToTarget(); } } @@ -352,12 +336,11 @@ public final class SIMRecords extends Handler implements SimConstants * Sets the SIM voice message waiting indicator records * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported * @param countWaiting The number of messages waiting, if known. Use - * -1 to indicate that an unknown number of + * -1 to indicate that an unknown number of * messages are waiting */ public void - setVoiceMessageWaiting(int line, int countWaiting) - { + setVoiceMessageWaiting(int line, int countWaiting) { if (line != 1) { // only profile 1 is supported return; @@ -374,14 +357,14 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = countWaiting; - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); try { if (efMWIS != null) { // TS 51.011 10.3.45 // lsb of byte 0 is 'voicemail' status - efMWIS[0] = (byte)((efMWIS[0] & 0xfe) + efMWIS[0] = (byte)((efMWIS[0] & 0xfe) | (countVoiceMessages == 0 ? 0 : 1)); // byte 1 is the number of voice messages waiting @@ -393,17 +376,17 @@ public final class SIMRecords extends Handler implements SimConstants efMWIS[1] = (byte) countWaiting; } - phone.mSIMFileHandler.updateEFLinearFixed( + phone.getIccFileHandler().updateEFLinearFixed( EF_MWIS, 1, efMWIS, null, obtainMessage (EVENT_UPDATE_DONE, EF_MWIS)); - } + } if (efCPHS_MWI != null) { // Refer CPHS4_2.WW6 B4.2.3 - efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0) + efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0) | (countVoiceMessages == 0 ? 0x5 : 0xa)); - phone.mSIMFileHandler.updateEFTransparent( + phone.getIccFileHandler().updateEFTransparent( EF_VOICE_MAIL_INDICATOR_CPHS, efCPHS_MWI, obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS)); } @@ -413,22 +396,6 @@ public final class SIMRecords extends Handler implements SimConstants } } - /** @return true if there are messages waiting, false otherwise. */ - public boolean getVoiceMessageWaiting() - { - return countVoiceMessages != 0; - } - - /** - * Returns number of voice messages waiting, if available - * If not available (eg, on an older CPHS SIM) -1 is returned if - * getVoiceMessageWaiting() is true - */ - public int getCountVoiceMessages() - { - return countVoiceMessages; - } - public boolean getVoiceCallForwardingFlag() { return callForwardingEnabled; } @@ -439,7 +406,7 @@ public final class SIMRecords extends Handler implements SimConstants callForwardingEnabled = enable; - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); try { if (mEfCfis != null) { @@ -453,7 +420,7 @@ public final class SIMRecords extends Handler implements SimConstants // TODO: Should really update other fields in EF_CFIS, eg, // dialing number. We don't read or use it right now. - phone.mSIMFileHandler.updateEFLinearFixed( + phone.getIccFileHandler().updateEFLinearFixed( EF_CFIS, 1, mEfCfis, null, obtainMessage (EVENT_UPDATE_DONE, EF_CFIS)); } @@ -467,7 +434,7 @@ public final class SIMRecords extends Handler implements SimConstants | CFF_UNCONDITIONAL_DEACTIVE); } - phone.mSIMFileHandler.updateEFTransparent( + phone.getIccFileHandler().updateEFTransparent( EF_CFF_CPHS, mEfCff, obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS)); } @@ -496,8 +463,7 @@ public final class SIMRecords extends Handler implements SimConstants /** Returns the 5 or 6 digit MCC/MNC of the operator that * provided the SIM card. Returns null of SIM is not yet ready */ - String getSIMOperatorNumeric() - { + String getSIMOperatorNumeric() { if (imsi == null) { return null; } @@ -517,17 +483,8 @@ public final class SIMRecords extends Handler implements SimConstants return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); } - - boolean getRecordsLoaded() - { - if (recordsToLoad == 0 && recordsRequested == true) { - return true; - } else { - return false; - } - } - - /** + + /** * If the timezone is not already set, set it based on the MCC of the SIM. * @param mcc Mobile Country Code of the SIM */ @@ -557,8 +514,7 @@ public final class SIMRecords extends Handler implements SimConstants } //***** Overridden from Handler - public void handleMessage(Message msg) - { + public void handleMessage(Message msg) { AsyncResult ar; AdnRecord adn; @@ -573,19 +529,19 @@ public final class SIMRecords extends Handler implements SimConstants case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: onRadioOffOrNotAvailable(); - break; + break; /* IO events */ case EVENT_GET_IMSI_DONE: isRecordLoadResponse = true; - + ar = (AsyncResult)msg.obj; if (ar.exception != null) { Log.e(LOG_TAG, "Exception querying IMSI, Exception:" + ar.exception); break; - } - + } + imsi = (String) ar.result; // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more @@ -594,11 +550,11 @@ public final class SIMRecords extends Handler implements SimConstants Log.e(LOG_TAG, "invalid IMSI " + imsi); imsi = null; } - + Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx"); - phone.mSimCard.updateImsiConfiguration(imsi); - phone.mSimCard.broadcastSimStateChangedIntent( - SimCard.INTENT_VALUE_SIM_IMSI, null); + ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi); + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + SimCard.INTENT_VALUE_ICC_IMSI, null); int mcc = Integer.parseInt(imsi.substring(0, 3)); setTimezoneFromMccIfNeeded(mcc); @@ -616,7 +572,7 @@ public final class SIMRecords extends Handler implements SimConstants if (ar.exception == null) { // Refer TS 51.011 Section 10.3.44 for content details Log.d(LOG_TAG, "EF_MBI: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); // Voice mail record number stored first mailboxIndex = (int)data[0] & 0xff; @@ -651,20 +607,20 @@ public final class SIMRecords extends Handler implements SimConstants ar = (AsyncResult)msg.obj; if (ar.exception != null) { - - Log.d(LOG_TAG, "Invalid or missing EF" + + Log.d(LOG_TAG, "Invalid or missing EF" + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]")); // Bug #645770 fall back to CPHS // FIXME should use SST to decide if (msg.what == EVENT_GET_MBDN_DONE) { - //load CPHS on fail... + //load CPHS on fail... // FIXME right now, only load line1's CPHS voice mail entry recordsToLoad += 1; new AdnRecordLoader(phone).loadFromEF( - EF_MAILBOX_CPHS, EF_EXT1, 1, + EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); } break; @@ -672,7 +628,8 @@ public final class SIMRecords extends Handler implements SimConstants adn = (AdnRecord)ar.result; - Log.d(LOG_TAG, "VM: " + adn + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]")); + Log.d(LOG_TAG, "VM: " + adn + + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]")); if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) { // Bug #645770 fall back to CPHS @@ -680,7 +637,7 @@ public final class SIMRecords extends Handler implements SimConstants // FIXME right now, only load line1's CPHS voice mail entry recordsToLoad += 1; new AdnRecordLoader(phone).loadFromEF( - EF_MAILBOX_CPHS, EF_EXT1, 1, + EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); break; @@ -730,7 +687,7 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_MWIS: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); efMWIS = data; @@ -744,11 +701,11 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = data[1] & 0xff; if (voiceMailWaiting && countVoiceMessages == 0) { - // Unknown count = -1 + // Unknown count = -1 countVoiceMessages = -1; } - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); break; case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE: @@ -777,7 +734,7 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = 0; } - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); } break; @@ -786,13 +743,13 @@ public final class SIMRecords extends Handler implements SimConstants ar = (AsyncResult)msg.obj; data = (byte[])ar.result; - + if (ar.exception != null) { break; - } + } + + iccid = IccUtils.bcdToString(data, 0, data.length); - iccid = SimUtils.bcdToString(data, 0, data.length); - Log.d(LOG_TAG, "iccid: " + iccid); break; @@ -809,7 +766,7 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_AD: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); if (data.length < 3) { Log.d(LOG_TAG, "SIMRecords: Corrupt AD data on SIM"); @@ -851,14 +808,14 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_CFF_CPHS: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); mEfCff = data; if (mEfCfis == null) { callForwardingEnabled = ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE); - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); } break; @@ -872,7 +829,7 @@ public final class SIMRecords extends Handler implements SimConstants break; } - parseEfSpdi(data); + parseEfSpdi(data); break; case EVENT_UPDATE_DONE: @@ -896,8 +853,8 @@ public final class SIMRecords extends Handler implements SimConstants for ( ; tlv.isValidObject() ; tlv.nextObject()) { if (tlv.getTag() == TAG_FULL_NETWORK_NAME) { - pnnHomeName - = SimUtils.networkNameToString( + pnnHomeName + = IccUtils.networkNameToString( tlv.getData(), 0, tlv.getData().length); break; } @@ -931,7 +888,8 @@ public final class SIMRecords extends Handler implements SimConstants + ar.exception + " length " + index.length); } else { Log.d(LOG_TAG, "READ EF_SMS RECORD index=" + index[0]); - phone.mSIMFileHandler.loadEFLinearFixed(EF_SMS,index[0],obtainMessage(EVENT_GET_SMS_DONE)); + phone.getIccFileHandler().loadEFLinearFixed(EF_SMS,index[0], + obtainMessage(EVENT_GET_SMS_DONE)); } break; @@ -955,7 +913,7 @@ public final class SIMRecords extends Handler implements SimConstants break; } - //Log.d(LOG_TAG, "SST: " + SimUtils.bytesToHexString(data)); + //Log.d(LOG_TAG, "SST: " + IccUtils.bytesToHexString(data)); break; case EVENT_GET_INFO_CPHS_DONE: @@ -969,7 +927,7 @@ public final class SIMRecords extends Handler implements SimConstants mCphsInfo = (byte[])ar.result; - if (DBG) log("iCPHS: " + SimUtils.bytesToHexString(mCphsInfo)); + if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo)); break; case EVENT_SET_MBDN_DONE: @@ -1050,20 +1008,20 @@ public final class SIMRecords extends Handler implements SimConstants } Log.d(LOG_TAG, "EF_CFIS: " + - SimUtils.bytesToHexString(data)); + IccUtils.bytesToHexString(data)); mEfCfis = data; // Refer TS 51.011 Section 10.3.46 for the content description callForwardingEnabled = ((data[1] & 0x01) != 0); - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); break; }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal Log.w(LOG_TAG, "Exception parsing SIM record", exc); - } finally { + } finally { // Count up record load responses even if they are fails if (isRecordLoadResponse) { onRecordLoaded(); @@ -1076,12 +1034,12 @@ public final class SIMRecords extends Handler implements SimConstants case EF_MBDN: recordsToLoad++; new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6, - mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); + mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); break; case EF_MAILBOX_CPHS: recordsToLoad++; new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, - 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); + 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); break; default: // For now, fetch all records if this is not a @@ -1093,7 +1051,7 @@ 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; @@ -1102,7 +1060,7 @@ public final class SIMRecords extends Handler implements SimConstants switch ((result[0])) { case CommandsInterface.SIM_REFRESH_FILE_UPDATED: if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED"); - // result[1] contains the EFID of the updated file. + // result[1] contains the EFID of the updated file. int efid = result[1]; handleFileUpdate(efid); break; @@ -1130,8 +1088,7 @@ public final class SIMRecords extends Handler implements SimConstants } } - private void handleSms(byte[] ba) - { + private void handleSms(byte[] ba) { if (ba[0] != 0) Log.d("ENF", "status : " + ba[0]); @@ -1142,15 +1099,11 @@ public final class SIMRecords extends Handler implements SimConstants // Note: Data may include trailing FF's. That's OK; message // should still parse correctly. - byte[] nba = new byte[n - 1]; - System.arraycopy(ba, 1, nba, 0, n - 1); + byte[] pdu = new byte[n - 1]; + System.arraycopy(ba, 1, pdu, 0, n - 1); + SmsMessage message = SmsMessage.createFromPdu(pdu); - String pdu = SimUtils.bytesToHexString(nba); - // XXX first line is bogus - SmsMessage message = SmsMessage.newFromCMT( - new String[] { "", pdu }); - - phone.mSMS.dispatchMessage(message); + ((GSMPhone) phone).mSMS.dispatchMessage(message); } } @@ -1172,15 +1125,11 @@ public final class SIMRecords extends Handler implements SimConstants // Note: Data may include trailing FF's. That's OK; message // should still parse correctly. - byte[] nba = new byte[n - 1]; - System.arraycopy(ba, 1, nba, 0, n - 1); - - String pdu = SimUtils.bytesToHexString(nba); - // XXX first line is bogus - SmsMessage message = SmsMessage.newFromCMT( - new String[] { "", pdu }); + byte[] pdu = new byte[n - 1]; + System.arraycopy(ba, 1, pdu, 0, n - 1); + SmsMessage message = SmsMessage.createFromPdu(pdu); - phone.mSMS.dispatchMessage(message); + ((GSMPhone) phone).mSMS.dispatchMessage(message); // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 // 1 == "received by MS from network; message read" @@ -1188,18 +1137,14 @@ public final class SIMRecords extends Handler implements SimConstants ba[0] = 1; if (false) { // XXX writing seems to crash RdoServD - phone.mSIMFileHandler.updateEFLinearFixed(EF_SMS, i, ba, null, - obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); + phone.getIccFileHandler().updateEFLinearFixed(EF_SMS, + i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); } } } } - - //***** Private Methods - - private void onRecordLoaded() - { + protected void onRecordLoaded() { // One record loaded successfully or failed, In either case // we need to update the recordsToLoad count recordsToLoad -= 1; @@ -1211,21 +1156,19 @@ public final class SIMRecords extends Handler implements SimConstants recordsToLoad = 0; } } - - private void onAllRecordsLoaded() - { + + protected void onAllRecordsLoaded() { Log.d(LOG_TAG, "SIMRecords: record load complete"); String operator = getSIMOperatorNumeric(); // Some fields require more than one SIM record to set - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, operator); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator); if (imsi != null) { - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, - MccTable.countryCodeForMcc( - Integer.parseInt(imsi.substring(0,3)))); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, + MccTable.countryCodeForMcc(Integer.parseInt(imsi.substring(0,3)))); } else { Log.e("SIM", "[SIMRecords] onAllRecordsLoaded: imsi is NULL!"); @@ -1236,16 +1179,19 @@ public final class SIMRecords extends Handler implements SimConstants recordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); - phone.mSimCard.broadcastSimStateChangedIntent( - SimCard.INTENT_VALUE_SIM_LOADED, null); + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + SimCard.INTENT_VALUE_ICC_LOADED, null); } + //***** Private methods + private void setSpnFromConfig(String carrier) { if (mSpnOverride.containsCarrier(carrier)) { spn = mSpnOverride.getSpn(carrier); } } + private void setVoiceMailByCountry (String spn) { if (mVmConfig.containsCarrier(spn)) { isVoiceMailFixed = true; @@ -1258,22 +1204,22 @@ public final class SIMRecords extends Handler implements SimConstants /* broadcast intent SIM_READY here so that we can make sure READY is sent before IMSI ready */ - phone.mSimCard.broadcastSimStateChangedIntent( - SimCard.INTENT_VALUE_SIM_READY, null); + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + SimCard.INTENT_VALUE_ICC_READY, null); fetchSimRecords(); } private void fetchSimRecords() { recordsRequested = true; + IccFileHandler iccFh = phone.getIccFileHandler(); - Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad); + Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad); phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_ICCID, - obtainMessage(EVENT_GET_ICCID_DONE)); + iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); recordsToLoad++; // FIXME should examine EF[MSISDN]'s capability configuration @@ -1283,17 +1229,14 @@ public final class SIMRecords extends Handler implements SimConstants recordsToLoad++; // Record number is subscriber profile - phone.mSIMFileHandler.loadEFLinearFixed(EF_MBI, 1, - obtainMessage(EVENT_GET_MBI_DONE)); + iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_AD, - obtainMessage(EVENT_GET_AD_DONE)); + iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); recordsToLoad++; // Record number is subscriber profile - phone.mSIMFileHandler.loadEFLinearFixed(EF_MWIS, 1, - obtainMessage(EVENT_GET_MWIS_DONE)); + iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); recordsToLoad++; @@ -1301,50 +1244,49 @@ public final class SIMRecords extends Handler implements SimConstants // the same info as EF[MWIS]. If both exist, both are updated // but the EF[MWIS] data is preferred // Please note this must be loaded after EF[MWIS] - phone.mSIMFileHandler.loadEFTransparent( - EF_VOICE_MAIL_INDICATOR_CPHS, + iccFh.loadEFTransparent( + EF_VOICE_MAIL_INDICATOR_CPHS, obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); recordsToLoad++; // Same goes for Call Forward Status indicator: fetch both // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. - phone.mSIMFileHandler.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); + iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_CFF_CPHS, - obtainMessage(EVENT_GET_CFF_DONE)); + iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); recordsToLoad++; getSpnFsm(true, null); - phone.mSIMFileHandler.loadEFTransparent(EF_SPDI, - obtainMessage(EVENT_GET_SPDI_DONE)); + iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFLinearFixed(EF_PNN, 1, - obtainMessage(EVENT_GET_PNN_DONE)); + iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_SST, - obtainMessage(EVENT_GET_SST_DONE)); + iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); recordsToLoad++; - phone.mSIMFileHandler.loadEFTransparent(EF_INFO_CPHS, - obtainMessage(EVENT_GET_INFO_CPHS_DONE)); + iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); recordsToLoad++; // XXX should seek instead of examining them all if (false) { // XXX - phone.mSIMFileHandler.loadEFLinearFixedAll(EF_SMS, - obtainMessage(EVENT_GET_ALL_SMS_DONE)); + iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); recordsToLoad++; } if (CRASH_RIL) { - String sms = "0107912160130310f20404d0110041007030208054832b0120ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; - byte[] ba = SimUtils.hexStringToBytes(sms); - - phone.mSIMFileHandler.updateEFLinearFixed(EF_SMS, 1, ba, null, + String sms = "0107912160130310f20404d0110041007030208054832b0120" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffff"; + byte[] ba = IccUtils.hexStringToBytes(sms); + + iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); } } @@ -1356,7 +1298,7 @@ public final class SIMRecords extends Handler implements SimConstants * * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. */ - int getDisplayRule(String plmn) { + protected int getDisplayRule(String plmn) { int rule; if (spn == null || spnDisplayCondition == -1) { // EF_SPN was not found on the SIM, or not yet loaded. Just show ONS. @@ -1431,7 +1373,7 @@ public final class SIMRecords extends Handler implements SimConstants case INIT: spn = null; - phone.mSIMFileHandler.loadEFTransparent( EF_SPN, + phone.getIccFileHandler().loadEFTransparent( EF_SPN, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; @@ -1441,20 +1383,20 @@ public final class SIMRecords extends Handler implements SimConstants if (ar != null && ar.exception == null) { data = (byte[]) ar.result; spnDisplayCondition = 0xff & data[0]; - spn = SimUtils.adnStringFieldToString(data, 1, data.length - 1); + spn = IccUtils.adnStringFieldToString(data, 1, data.length - 1); if (DBG) log("Load EF_SPN: " + spn + " spnDisplayCondition: " + spnDisplayCondition); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); spnState = Get_Spn_Fsm_State.IDLE; } else { - phone.mSIMFileHandler.loadEFTransparent( EF_SPN_CPHS, + phone.getIccFileHandler().loadEFTransparent( EF_SPN_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; spnState = Get_Spn_Fsm_State.READ_SPN_CPHS; - + // See TS 51.011 10.3.11. Basically, default to // show PLMN always, and SPN also if roaming. spnDisplayCondition = -1; @@ -1463,16 +1405,16 @@ public final class SIMRecords extends Handler implements SimConstants case READ_SPN_CPHS: if (ar != null && ar.exception == null) { data = (byte[]) ar.result; - spn = SimUtils.adnStringFieldToString( + spn = IccUtils.adnStringFieldToString( data, 0, data.length - 1 ); if (DBG) log("Load EF_SPN_CPHS: " + spn); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); spnState = Get_Spn_Fsm_State.IDLE; } else { - phone.mSIMFileHandler.loadEFTransparent( EF_SPN_SHORT_CPHS, - obtainMessage(EVENT_GET_SPN_DONE)); + phone.getIccFileHandler().loadEFTransparent( + EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; spnState = Get_Spn_Fsm_State.READ_SPN_SHORT_CPHS; @@ -1481,11 +1423,11 @@ public final class SIMRecords extends Handler implements SimConstants case READ_SPN_SHORT_CPHS: if (ar != null && ar.exception == null) { data = (byte[]) ar.result; - spn = SimUtils.adnStringFieldToString( + spn = IccUtils.adnStringFieldToString( data, 0, data.length - 1); if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); }else { if (DBG) log("No SPN loaded in either CHPS or 3GPP"); } @@ -1503,8 +1445,7 @@ public final class SIMRecords extends Handler implements SimConstants * are treated specially when determining SPN display */ private void - parseEfSpdi(byte[] data) - { + parseEfSpdi(byte[] data) { SimTlv tlv = new SimTlv(data, 0, data.length); byte[] plmnEntries = null; @@ -1524,8 +1465,8 @@ public final class SIMRecords extends Handler implements SimConstants spdiNetworks = new ArrayList(plmnEntries.length / 3); for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { - String plmnCode; - plmnCode = SimUtils.bcdToString(plmnEntries, i, 3); + String plmnCode; + plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); // Valid operator codes are 5 or 6 digits if (plmnCode.length() >= 5) { @@ -1543,7 +1484,8 @@ public final class SIMRecords extends Handler implements SimConstants return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); } - private void log(String s) { + protected void log(String s) { Log.d(LOG_TAG, "[SIMRecords] " + s); } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java similarity index 86% rename from telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java rename to telephony/java/com/android/internal/telephony/gsm/SimCard.java index a4cded9ddc4daac9f15d0ede9affd8bc7664a988..9af3aa6a2e1f74f6c687772dfabd4176e9f1bc17 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java @@ -16,6 +16,9 @@ package com.android.internal.telephony.gsm; +import android.app.ActivityManagerNative; +import android.content.Intent; +import android.content.res.Configuration; import android.os.AsyncResult; import android.os.RemoteException; import android.os.Handler; @@ -23,32 +26,34 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.util.Log; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyProperties; + +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.TelephonyIntents; -import android.content.Intent; -import android.content.res.Configuration; -import android.app.ActivityManagerNative; +import com.android.internal.telephony.TelephonyProperties; import static android.Manifest.permission.READ_PHONE_STATE; /** + * Note: this class shares common code with RuimCard, consider a base class to minimize code + * duplication. * {@hide} */ -public final class GsmSimCard extends Handler implements SimCard { +public final class SimCard extends Handler implements IccCard { static final String LOG_TAG="GSM"; - + //***** Instance Variables private static final boolean DBG = true; private GSMPhone phone; - private CommandsInterface.SimStatus status = null; + private CommandsInterface.IccStatus status = null; + private boolean mDesiredPinLocked; + private boolean mDesiredFdnEnabled; private boolean mSimPinLocked = true; // Default to locked private boolean mSimFdnEnabled = false; // Default to disabled. // Will be updated when SIM_READY. - private boolean mDesiredPinLocked; - private boolean mDesiredFdnEnabled; //***** Constants @@ -72,8 +77,7 @@ public final class GsmSimCard extends Handler implements SimCard { //***** Constructor - GsmSimCard(GSMPhone phone) - { + SimCard(GSMPhone phone) { this.phone = phone; phone.mCM.registerForSIMLockedOrAbsent( @@ -87,12 +91,22 @@ public final class GsmSimCard extends Handler implements SimCard { updateStateProperty(); } - + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForSIMLockedOrAbsent(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + phone.mCM.unregisterForSIMReady(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimCard finalized"); + } + //***** SimCard implementation public State - getState() - { + getState() { if (status == null) { switch(phone.mCM.getRadioState()) { /* This switch block must not return anything in @@ -111,12 +125,12 @@ public final class GsmSimCard extends Handler implements SimCard { } } else { switch (status) { - case SIM_ABSENT: return State.ABSENT; - case SIM_NOT_READY: return State.UNKNOWN; - case SIM_READY: return State.READY; - case SIM_PIN: return State.PIN_REQUIRED; - case SIM_PUK: return State.PUK_REQUIRED; - case SIM_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; + case ICC_ABSENT: return State.ABSENT; + case ICC_NOT_READY: return State.UNKNOWN; + case ICC_READY: return State.READY; + case ICC_PIN: return State.PIN_REQUIRED; + case ICC_PUK: return State.PUK_REQUIRED; + case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; } } @@ -129,8 +143,7 @@ public final class GsmSimCard extends Handler implements SimCard { private RegistrantList networkLockedRegistrants = new RegistrantList(); - public void registerForAbsent(Handler h, int what, Object obj) - { + public void registerForAbsent(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); absentRegistrants.add(r); @@ -139,9 +152,9 @@ public final class GsmSimCard extends Handler implements SimCard { r.notifyRegistrant(); } } - + public void unregisterForAbsent(Handler h) { - absentRegistrants.remove(h); + absentRegistrants.remove(h); } public void registerForNetworkLocked(Handler h, int what, Object obj) { @@ -155,11 +168,10 @@ public final class GsmSimCard extends Handler implements SimCard { } public void unregisterForNetworkLocked(Handler h) { - networkLockedRegistrants.remove(h); + networkLockedRegistrants.remove(h); } - - public void registerForLocked(Handler h, int what, Object obj) - { + + public void registerForLocked(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); pinLockedRegistrants.add(r); @@ -169,50 +181,44 @@ public final class GsmSimCard extends Handler implements SimCard { } } - public void unregisterForLocked(Handler h) - { + public void unregisterForLocked(Handler h) { pinLockedRegistrants.remove(h); } - public void supplyPin (String pin, Message onComplete) - { - phone.mCM.supplySimPin(pin, + public void supplyPin (String pin, Message onComplete) { + phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyPuk (String puk, String newPin, Message onComplete) - { - phone.mCM.supplySimPuk(puk, newPin, + public void supplyPuk (String puk, String newPin, Message onComplete) { + phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyPin2 (String pin2, Message onComplete) - { - phone.mCM.supplySimPin2(pin2, + public void supplyPin2 (String pin2, Message onComplete) { + phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyPuk2 (String puk2, String newPin2, Message onComplete) - { - phone.mCM.supplySimPuk2(puk2, newPin2, + public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { + phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public void supplyNetworkDepersonalization (String pin, Message onComplete) - { + public void supplyNetworkDepersonalization (String pin, Message onComplete) { if(DBG) log("Network Despersonalization: " + pin); phone.mCM.supplyNetworkDepersonalization(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } - public boolean getSimLockEnabled() { + public boolean getIccLockEnabled() { return mSimPinLocked; } - public boolean getSimFdnEnabled() { + public boolean getIccFdnEnabled() { return mSimFdnEnabled; } - public void setSimLockEnabled (boolean enabled, + public void setIccLockEnabled (boolean enabled, String password, Message onComplete) { int serviceClassX; serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + @@ -226,7 +232,7 @@ public final class GsmSimCard extends Handler implements SimCard { obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); } - public void setSimFdnEnabled (boolean enabled, + public void setIccFdnEnabled (boolean enabled, String password, Message onComplete) { int serviceClassX; serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + @@ -241,18 +247,18 @@ public final class GsmSimCard extends Handler implements SimCard { obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); } - public void changeSimLockPassword(String oldPassword, String newPassword, + public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) { if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeSimPin(oldPassword, newPassword, + phone.mCM.changeIccPin(oldPassword, newPassword, obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete)); } - public void changeSimFdnPassword(String oldPassword, String newPassword, + public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) { if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeSimPin2(oldPassword, newPassword, + phone.mCM.changeIccPin2(oldPassword, newPassword, obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete)); } @@ -275,11 +281,11 @@ public final class GsmSimCard extends Handler implements SimCard { case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: status = null; updateStateProperty(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_NOT_READY, null); + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_NOT_READY, null); break; case EVENT_SIM_READY: //TODO: put facility read in SIM_READY now, maybe in REG_NW - phone.mCM.getSimStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); phone.mCM.queryFacilityLock ( CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); @@ -288,7 +294,7 @@ public final class GsmSimCard extends Handler implements SimCard { obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); break; case EVENT_SIM_LOCKED_OR_ABSENT: - phone.mCM.getSimStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); + phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); phone.mCM.queryFacilityLock ( CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); @@ -306,7 +312,7 @@ public final class GsmSimCard extends Handler implements SimCard { // TODO should abstract these exceptions AsyncResult.forMessage(((Message)ar.userObj)).exception = ar.exception; - phone.mCM.getSimStatus( + phone.mCM.getIccStatus( obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); break; case EVENT_REPOLL_STATUS_DONE: @@ -415,24 +421,24 @@ public final class GsmSimCard extends Handler implements SimCard { private void getSimStatusDone(AsyncResult ar) { if (ar.exception != null) { - Log.e(LOG_TAG,"Error getting SIM status. " - + "RIL_REQUEST_GET_SIM_STATUS should " + Log.e(LOG_TAG,"Error getting ICC status. " + + "RIL_REQUEST_GET_ICC_STATUS should " + "never return an error", ar.exception); return; } - CommandsInterface.SimStatus newStatus - = (CommandsInterface.SimStatus) ar.result; + CommandsInterface.IccStatus newStatus + = (CommandsInterface.IccStatus) ar.result; handleSimStatus(newStatus); } private void - handleSimStatus(CommandsInterface.SimStatus newStatus) { + handleSimStatus(CommandsInterface.IccStatus newStatus) { boolean transitionedIntoPinLocked; boolean transitionedIntoAbsent; boolean transitionedIntoNetworkLocked; - + SimCard.State oldState, newState; oldState = getState(); @@ -451,17 +457,17 @@ public final class GsmSimCard extends Handler implements SimCard { if (transitionedIntoPinLocked) { if(DBG) log("Notify SIM pin or puk locked."); pinLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_LOCKED, + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, (newState == State.PIN_REQUIRED) ? INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); } else if (transitionedIntoAbsent) { if(DBG) log("Notify SIM missing."); absentRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_ABSENT, null); + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_ABSENT, null); } else if (transitionedIntoNetworkLocked) { if(DBG) log("Notify SIM network locked."); networkLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_LOCKED, + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, INTENT_VALUE_LOCKED_NETWORK); } } @@ -469,7 +475,7 @@ public final class GsmSimCard extends Handler implements SimCard { public void broadcastSimStateChangedIntent(String value, String reason) { Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName()); - intent.putExtra(SimCard.INTENT_KEY_SIM_STATE, value); + intent.putExtra(SimCard.INTENT_KEY_ICC_STATE, value); intent.putExtra(SimCard.INTENT_KEY_LOCKED_REASON, reason); if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value + " reason " + reason); diff --git a/telephony/java/com/android/internal/telephony/gsm/SimConstants.java b/telephony/java/com/android/internal/telephony/gsm/SimConstants.java deleted file mode 100644 index a7e3bbcbc9cd302ccefc1dd028b0bd1baf204461..0000000000000000000000000000000000000000 --- a/telephony/java/com/android/internal/telephony/gsm/SimConstants.java +++ /dev/null @@ -1,55 +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; - -/** - * {@hide} - */ -public interface SimConstants { - // SIM file ids from TS 51.011 - public static final int EF_ADN = 0x6F3A; - public static final int EF_FDN = 0x6F3B; - public static final int EF_SDN = 0x6F49; - public static final int EF_EXT1 = 0x6F4A; - public static final int EF_EXT2 = 0x6F4B; - public static final int EF_EXT3 = 0x6F4C; - public static final int EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN] - public static final int EF_MWIS = 0x6FCA; - public static final int EF_MBDN = 0x6fc7; - public static final int EF_PNN = 0x6fc5; - public static final int EF_SPN = 0x6F46; - public static final int EF_SMS = 0x6F3C; - public static final int EF_ICCID = 0x2fe2; - public static final int EF_AD = 0x6FAD; - public static final int EF_MBI = 0x6fc9; - public static final int EF_MSISDN = 0x6f40; - public static final int EF_SPDI = 0x6fcd; - public static final int EF_SST = 0x6f38; - public static final int EF_CFIS = 0x6FCB; - public static final int EF_IMG = 0x4f20; - - // SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6 - public static final int EF_MAILBOX_CPHS = 0x6F17; - public static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11; - public static final int EF_CFF_CPHS = 0x6F13; - public static final int EF_SPN_CPHS = 0x6f14; - public static final int EF_SPN_SHORT_CPHS = 0x6f18; - public static final int EF_INFO_CPHS = 0x6f16; - - // SMS record length from TS 51.011 10.5.3 - static public final int SMS_RECORD_LENGTH = 176; -} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java index 7cc9a80b8d260135d78855e048f3d19a2e3fb029..076da6bcf68c5b7163e16f033e9702c7f04080c1 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java @@ -25,6 +25,11 @@ import android.os.ServiceManager; import android.telephony.PhoneNumberUtils; import android.util.Log; +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.PhoneProxy; + import java.util.ArrayList; import java.util.List; @@ -32,247 +37,65 @@ import java.util.List; * SimPhoneBookInterfaceManager to provide an inter-process communication to * access ADN-like SIM records. */ -public class SimPhoneBookInterfaceManager extends ISimPhoneBook.Stub { - static final String LOG_TAG = "GSM"; - static final boolean DBG = false; - private GSMPhone phone; - private AdnRecordCache adnCache; - private final Object mLock = new Object(); - private int recordSize[]; - private boolean success; - private List records; - private static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false; +public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { + static final String LOG_TAG = "GSM"; - private static final int EVENT_GET_SIZE_DONE = 1; - private static final int EVENT_LOAD_DONE = 2; - private static final int EVENT_UPDATE_DONE = 3; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { AsyncResult ar; - switch (msg.what) { - case EVENT_GET_SIZE_DONE: - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - recordSize = (int[])ar.result; - // recordSize[0] is the record length - // recordSize[1] is the total length of the EF file - // recordSize[2] is the number of records in the EF file - log("GET_RECORD_SIZE Size " + recordSize[0] + - " total " + recordSize[1] + - " #record " + recordSize[2]); - mLock.notifyAll(); - } - } - break; - case EVENT_UPDATE_DONE: - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - success = (ar.exception == null); - mLock.notifyAll(); - } - break; - case EVENT_LOAD_DONE: - ar = (AsyncResult)msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - records = (List) - ((ArrayList) ar.result); - } else { - if(DBG) log("Cannot load ADN records"); - if (records != null) { - records.clear(); - } - } - mLock.notifyAll(); - } + switch(msg.what) { + default: + mBaseHandler.handleMessage(msg); break; } } }; public SimPhoneBookInterfaceManager(GSMPhone phone) { - this.phone = phone; + super(phone); adnCache = phone.mSIMRecords.getAdnCache(); - publish(); + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy } - private void publish() { - ServiceManager.addService("simphonebook", this); + public void dispose() { + super.dispose(); } - /** - * Replace oldAdn with newAdn in ADN-like record in EF - * - * getAdnRecordsInEf must be called at least once before this function, - * otherwise an error will be returned - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param oldTag adn tag to be replaced - * @param oldPhoneNumber adn number to be replaced - * Set both oldTag and oldPhoneNubmer to "" means to replace an - * empty record, aka, insert new record - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number ot be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfBySearch (int efid, - String oldTag, String oldPhoneNumber, - String newTag, String newPhoneNumber, String pin2) { - - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.WRITE_CONTACTS permission"); - } - - - if (DBG) log("updateAdnRecordsInEfBySearch: efid=" + efid + - " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" + - " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); - synchronized(mLock) { - checkThread(); - success = false; - Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber); - AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); - adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to update by search"); - } - } - return success; - } - - /** - * Update an ADN-like EF record by record index - * - * This is useful for iteration the whole ADN file, such as write the whole - * phone book or erase/format the whole phonebook - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number to be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param index is 1-based adn record index to be updated - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfByIndex(int efid, String newTag, - String newPhoneNumber, int index, String pin2) { - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.WRITE_CONTACTS permission"); - } - - if (DBG) log("updateAdnRecordsInEfByIndex: efid=" + efid + - " Index=" + index + " ==> " + - "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); - synchronized(mLock) { - checkThread(); - success = false; - Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); - adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to update by index"); - } - } - return success; + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimPhoneBookInterfaceManager finalized"); } - /** - * Get the capacity of records in efid - * - * @param efid the EF id of a ADN-like SIM - * @return int[3] array - * recordSizes[0] is the single record length - * recordSizes[1] is the total length of the EF file - * recordSizes[2] is the number of records in the EF file - */ public int[] getAdnRecordsSize(int efid) { - if (DBG) log("getAdnRecordsSize: efid=" + efid); + if (DBG) logd("getAdnRecordsSize: efid=" + efid); synchronized(mLock) { checkThread(); recordSize = new int[3]; - Message response = mHandler.obtainMessage(EVENT_GET_SIZE_DONE); - phone.mSIMFileHandler.getEFLinearRecordSize(efid, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); - } - } - return recordSize; - } + //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling + Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE); - /** - * Loads the AdnRecords in efid and returns them as a - * List of AdnRecords - * - * throws SecurityException if no READ_CONTACTS permission - * - * @param efid the EF id of a ADN-like SIM - * @return List of AdnRecord - */ - public List getAdnRecordsInEf(int efid) { - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.READ_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.READ_CONTACTS permission"); - } - - if (DBG) log("getAdnRecordsInEF: efid=" + efid); - - synchronized(mLock) { - checkThread(); - Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); - adnCache.requestLoadAllAdnLike(efid, response); + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); try { mLock.wait(); } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); + logd("interrupted while trying to load from the SIM"); } } - return records; + + return recordSize; } - private void checkThread() { - if (!ALLOW_SIM_OP_IN_UI_THREAD) { - // Make sure this isn't the UI thread, since it will block - if (mHandler.getLooper().equals(Looper.myLooper())) { - Log.e(LOG_TAG, "query() called on the main UI thread!"); - throw new IllegalStateException("You cannot call query on this provder from the main UI thread."); - } - } + protected void logd(String msg) { + Log.d(LOG_TAG, "[SimPbInterfaceManager] " + msg); } - private void log(String msg) { - Log.d(LOG_TAG, "[SpbInterfaceManager] " + msg); + protected void loge(String msg) { + Log.e(LOG_TAG, "[SimPbInterfaceManager] " + msg); } } + diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java index c3df0d0d12babf622dabeac700a432383cf6ee71..875d8d01f81a3dc5d04b366c8275c3227e3ef083 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java @@ -16,27 +16,31 @@ package com.android.internal.telephony.gsm; -import android.app.PendingIntent; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; -import android.os.ServiceManager; -import android.telephony.gsm.SmsManager; import android.util.Log; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.SmsRawData; + import java.util.ArrayList; import java.util.List; +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; + /** * SimSmsInterfaceManager to provide an inter-process communication to * access Sms in Sim. */ -public class SimSmsInterfaceManager extends ISms.Stub { +public class SimSmsInterfaceManager extends IccSmsInterfaceManager { static final String LOG_TAG = "GSM"; - static final boolean DBG = false; + static final boolean DBG = true; - private GSMPhone mPhone; private final Object mLock = new Object(); private boolean mSuccess; private List mSms; @@ -76,33 +80,31 @@ public class SimSmsInterfaceManager extends ISms.Stub { }; public SimSmsInterfaceManager(GSMPhone phone) { - this.mPhone = phone; - ServiceManager.addService("isms", this); + super(phone); + mDispatcher = new GsmSMSDispatcher(phone); } - private void enforceReceiveAndSend(String message) { - Context context = mPhone.getContext(); + public void dispose() { + } - context.enforceCallingPermission( - "android.permission.RECEIVE_SMS", message); - context.enforceCallingPermission( - "android.permission.SEND_SMS", message); + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimSmsInterfaceManager finalized"); } /** * Update the specified message on the SIM. * * @param index record index of message to update - * @param status new message status (STATUS_ON_SIM_READ, - * STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT, - * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) + * @param status new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) * @param pdu the raw PDU to store * @return success or not * */ public boolean - updateMessageOnSimEf(int index, int status, byte[] pdu) { - if (DBG) log("updateMessageOnSimEf: index=" + index + + updateMessageOnIccEf(int index, int status, byte[] pdu) { + if (DBG) log("updateMessageOnIccEf: index=" + index + " status=" + status + " ==> " + "("+ pdu + ")"); enforceReceiveAndSend("Updating message on SIM"); @@ -110,13 +112,14 @@ public class SimSmsInterfaceManager extends ISms.Stub { mSuccess = false; Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - if (status == SmsManager.STATUS_ON_SIM_FREE) { + if (status == STATUS_ON_ICC_FREE) { // Special case FREE: call deleteSmsOnSim instead of // manipulating the SIM record mPhone.mCM.deleteSmsOnSim(index, response); } else { byte[] record = makeSmsRecordData(status, pdu); - mPhone.mSIMFileHandler.updateEFLinearFixed( SimConstants.EF_SMS, + ((SIMFileHandler)mPhone.getIccFileHandler()).updateEFLinearFixed( + IccConstants.EF_SMS, index, record, null, response); } try { @@ -132,21 +135,21 @@ public class SimSmsInterfaceManager extends ISms.Stub { * Copy a raw SMS PDU to the SIM. * * @param pdu the raw PDU to store - * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, - * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) * @return success or not * */ - public boolean copyMessageToSimEf(int status, byte[] pdu, byte[] smsc) { - if (DBG) log("copyMessageToSimEf: status=" + status + " ==> " + + public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { + if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + "pdu=("+ pdu + "), smsm=(" + smsc +")"); enforceReceiveAndSend("Copying message to SIM"); synchronized(mLock) { mSuccess = false; Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - mPhone.mCM.writeSmsToSim(status, SimUtils.bytesToHexString(smsc), - SimUtils.bytesToHexString(pdu), response); + mPhone.mCM.writeSmsToSim(status, IccUtils.bytesToHexString(smsc), + IccUtils.bytesToHexString(pdu), response); try { mLock.wait(); @@ -158,11 +161,11 @@ public class SimSmsInterfaceManager extends ISms.Stub { } /** - * Retrieves all messages currently stored on SIM. + * Retrieves all messages currently stored on ICC. * - * @return list of SmsRawData of all sms on SIM + * @return list of SmsRawData of all sms on ICC */ - public List getAllMessagesFromSimEf() { + public List getAllMessagesFromIccEf() { if (DBG) log("getAllMessagesFromEF"); Context context = mPhone.getContext(); @@ -172,7 +175,7 @@ public class SimSmsInterfaceManager extends ISms.Stub { "Reading messages from SIM"); synchronized(mLock) { Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); - mPhone.mSIMFileHandler.loadEFLinearFixedAll(SimConstants.EF_SMS, + ((SIMFileHandler)mPhone.getIccFileHandler()).loadEFLinearFixedAll(IccConstants.EF_SMS, response); try { @@ -184,119 +187,7 @@ public class SimSmsInterfaceManager extends ISms.Stub { return mSms; } - /** - * Send a Raw PDU SMS - * - * @param smsc the SMSC to send the message through, or NULL for the - * defatult SMSC - * @param pdu the raw PDU to send - * @param sentIntent if not NULL this Intent is - * broadcast when the message is sucessfully sent, or failed. - * The result code will be Activity.RESULT_OK for success, - * or one of these errors: - * RESULT_ERROR_GENERIC_FAILURE - * RESULT_ERROR_RADIO_OFF - * RESULT_ERROR_NULL_PDU. - * @param deliveryIntent if not NULL this Intent is - * broadcast when the message is delivered to the recipient. The - * raw pdu of the status report is in the extended data ("pdu"). - */ - public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - Context context = mPhone.getContext(); - - context.enforceCallingPermission( - "android.permission.SEND_SMS", - "Sending SMS message"); - if (DBG) log("sendRawPdu: smsc=" + smsc + - " pdu="+ pdu + " sentIntent" + sentIntent + - " deliveryIntent" + deliveryIntent); - mPhone.mSMS.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); - } - - /** - * Send a multi-part text based SMS. - * - * @param destinationAddress the address to send the message to - * @param scAddress is the service center address or null to use - * the current default SMSC - * @param parts an ArrayList of strings that, in order, - * comprise the original message - * @param sentIntents if not null, an ArrayList of - * PendingIntents (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be Activity.RESULT_OK for success, - * or one of these errors: - * RESULT_ERROR_GENERIC_FAILURE - * RESULT_ERROR_RADIO_OFF - * RESULT_ERROR_NULL_PDU. - * @param deliveryIntents if not null, an ArrayList of - * PendingIntents (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). - */ - public void sendMultipartText(String destinationAddress, String scAddress, List parts, - List sentIntents, List deliveryIntents) { - Context context = mPhone.getContext(); - - context.enforceCallingPermission( - "android.permission.SEND_SMS", - "Sending SMS message"); - if (DBG) log("sendMultipartText"); - mPhone.mSMS.sendMultipartText(destinationAddress, scAddress, (ArrayList) parts, - (ArrayList) sentIntents, (ArrayList) deliveryIntents); - } - - /** - * Generates an EF_SMS record from status and raw PDU. - * - * @param status Message status. See TS 51.011 10.5.3. - * @param pdu Raw message PDU. - * @return byte array for the record. - */ - private byte[] makeSmsRecordData(int status, byte[] pdu) { - byte[] data = new byte[SimConstants.SMS_RECORD_LENGTH]; - - // Status bits for this record. See TS 51.011 10.5.3 - data[0] = (byte)(status & 7); - - System.arraycopy(pdu, 0, data, 1, pdu.length); - - // Pad out with 0xFF's. - for (int j = pdu.length+1; j < SimConstants.SMS_RECORD_LENGTH; j++) { - data[j] = -1; - } - - return data; - } - - /** - * create SmsRawData lists from all sms record byte[] - * Use null to indicate "free" record - * - * @param messages List of message records from EF_SMS. - * @return SmsRawData list of all in-used records - */ - private ArrayList buildValidRawData(ArrayList messages) { - int count = messages.size(); - ArrayList ret; - - ret = new ArrayList(count); - - for (int i = 0; i < count; i++) { - byte[] ba = messages.get(i); - if (ba[0] == 0) { - ret.add(null); - } else { - ret.add(new SmsRawData(messages.get(i))); - } - } - - return ret; - } - - private void log(String msg) { - Log.d(LOG_TAG, "[SmsInterfaceManager] " + msg); + protected void log(String msg) { + Log.d(LOG_TAG, "[SimSmsInterfaceManager] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java index 00879ce657b6b5639505b1d51f435190d3e0b24d..30543c7becd178201732d7edba272e0021bf2feb 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java @@ -34,9 +34,8 @@ public class SimTlv int curDataOffset; int curDataLength; boolean hasValidTlvObject; - - public SimTlv(byte[] record, int offset, int length) - { + + public SimTlv(byte[] record, int offset, int length) { this.record = record; this.tlvOffset = offset; @@ -46,19 +45,15 @@ public class SimTlv hasValidTlvObject = parseCurrentTlvObject(); } - public boolean - nextObject() - { + public boolean nextObject() { if (!hasValidTlvObject) return false; curOffset = curDataOffset + curDataLength; - hasValidTlvObject = parseCurrentTlvObject(); + hasValidTlvObject = parseCurrentTlvObject(); return hasValidTlvObject; } - public boolean - isValidObject() - { + public boolean isValidObject() { return hasValidTlvObject; } @@ -68,9 +63,7 @@ public class SimTlv * 0 and 0xff are invalid tag values * valid tags range from 1 - 0xfe */ - public int - getTag() - { + public int getTag() { if (!hasValidTlvObject) return 0; return record[curOffset] & 0xff; } @@ -79,10 +72,8 @@ public class SimTlv * Returns data associated with current TLV object * returns null if !isValidObject() */ - - public byte[] - getData() - { + + public byte[] getData() { if (!hasValidTlvObject) return null; byte[] ret = new byte[curDataLength]; @@ -95,14 +86,12 @@ public class SimTlv * @return false on invalid record, true on valid record */ - private boolean - parseCurrentTlvObject() - { + private boolean parseCurrentTlvObject() { // 0x00 and 0xff are invalid tag values if (record[curOffset] == 0 || (record[curOffset] & 0xff) == 0xff) { return false; } - + try { if ((record[curOffset + 1] & 0xff) < 0x80) { // one byte length 0 - 0x7f diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..867b719d9db74dbbdf556d78363c3eb1527fdaad --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -0,0 +1,1058 @@ +/* + * 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.Parcel; +import android.telephony.PhoneNumberUtils; +import android.text.format.Time; +import android.util.Config; +import android.util.Log; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_8BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.ENCODING_UNKNOWN; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; +import static android.telephony.SmsMessage.MessageClass; + +/** + * A Short Message Service message. + * + */ +public class SmsMessage extends SmsMessageBase{ + static final String LOG_TAG = "GSM"; + + private MessageClass messageClass; + + /** + * TP-Message-Type-Indicator + * 9.2.3 + */ + private int mti; + + /** TP-Protocol-Identifier (TP-PID) */ + private int protocolIdentifier; + + // TP-Data-Coding-Scheme + // see TS 23.038 + private int dataCodingScheme; + + // TP-Reply-Path + // e.g. 23.040 9.2.2.1 + private boolean replyPathPresent = false; + + // "Message Marked for Automatic Deletion Group" + // 23.038 Section 4 + private boolean automaticDeletion; + + /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */ + private boolean forSubmit; + + /** The address of the receiver. */ + private GsmSmsAddress recipientAddress; + + /** Time when SMS-SUBMIT was delivered from SC to MSE. */ + private long dischargeTimeMillis; + + /** + * TP-Status - status of a previously submitted SMS. + * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; + * see TS 23.040, 9.2.3.15 for description of other possible values. + */ + private int status; + + /** + * TP-Status - status of a previously submitted SMS. + * This field is true iff the message is a SMS-STATUS-REPORT message. + */ + private boolean isStatusReportMessage = false; + + public static class SubmitPdu extends SubmitPduBase { + } + + /** + * Create an SmsMessage from a raw PDU. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the + * +CMT unsolicited response (PDU mode, of course) + * +CMT: [<alpha>], + * + * Only public for debugging + * + * {@hide} + */ + public static SmsMessage newFromCMT(String[] lines) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(IccUtils.hexStringToBytes(lines[1])); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** @hide */ + public static SmsMessage newFromCMTI(String line) { + // the thinking here is not to read the message immediately + // FTA test case + Log.e(LOG_TAG, "newFromCMTI: not yet supported"); + return null; + } + + /** @hide */ + public static SmsMessage newFromCDS(String line) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(IccUtils.hexStringToBytes(line)); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Note: This functionality is currently not supported in GSM mode. + * @hide + */ + public static SmsMessageBase newFromParcel(Parcel p){ + Log.w(LOG_TAG, "newFromParcel: is not supported in GSM mode."); + return null; + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by SmsManager.getAllMessagesFromSim + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + try { + SmsMessage msg = new SmsMessage(); + + msg.indexOnIcc = index; + + // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, + // or STORED_UNSENT + // See TS 51.011 10.5.3 + if ((data[0] & 1) == 0) { + Log.w(LOG_TAG, + "SMS parsing failed: Trying to parse a free record"); + return null; + } else { + msg.statusOnIcc = data[0] & 0x07; + } + + int size = data.length - 1; + + // Note: Data may include trailing FF's. That's OK; message + // should still parse correctly. + byte[] pdu = new byte[size]; + System.arraycopy(data, 1, pdu, 0, size); + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the + * length in bytes (not hex chars) less the SMSC header + */ + public static int getTPLayerLengthForPDU(String pdu) { + int len = pdu.length() / 2; + int smscLen = 0; + + smscLen = Integer.parseInt(pdu.substring(0, 2), 16); + + return len - smscLen - 1; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] header) { + + // Perform null parameter checks. + if (message == null || destinationAddress == null) { + return null; + } + + SubmitPdu ret = new SubmitPdu(); + // MTI = SMS-SUBMIT, UDHI = header != null + byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); + ByteArrayOutputStream bo = getSubmitPduHead( + scAddress, destinationAddress, mtiByte, + statusReportRequested, ret); + + try { + // First, try encoding it with the GSM alphabet + + // User Data (and length) + byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header); + + if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + // Default encoding, uncompressed + bo.write(0x00); + + // (no TP-Validity-Period) + + bo.write(userData, 0, userData.length); + } catch (EncodeException ex) { + byte[] userData, textPart; + // Encoding to the 7-bit alphabet failed. Let's see if we can + // send it as a UCS-2 encoded message + + try { + textPart = message.getBytes("utf-16be"); + } catch (UnsupportedEncodingException uex) { + Log.e(LOG_TAG, + "Implausible UnsupportedEncodingException ", + uex); + return null; + } + + if (header != null) { + userData = new byte[header.length + textPart.length]; + + System.arraycopy(header, 0, userData, 0, header.length); + System.arraycopy(textPart, 0, userData, header.length, textPart.length); + } + else { + userData = textPart; + } + + if (userData.length > MAX_USER_DATA_BYTES) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + // Class 3, UCS-2 encoding, uncompressed + bo.write(0x0b); + + // (no TP-Validity-Period) + + // TP-UDL + bo.write(userData.length); + + bo.write(userData, 0, userData.length); + } + + ret.encodedMessage = bo.toByteArray(); + return ret; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested) { + + return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param destinationPort the port to deliver the message to at the + * destination + * @param data the dat for the message + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { + Log.e(LOG_TAG, "SMS data message may only contain " + + (MAX_USER_DATA_BYTES - 7) + " bytes"); + return null; + } + + SubmitPdu ret = new SubmitPdu(); + ByteArrayOutputStream bo = getSubmitPduHead( + scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, + // TP-UDHI = true + statusReportRequested, ret); + + // TP-Data-Coding-Scheme + // No class, 8 bit data + bo.write(0x04); + + // (no TP-Validity-Period) + + // User data size + bo.write(data.length + 7); + + // User data header size + bo.write(0x06); // header is 6 octets + + // User data header, indicating the destination port + bo.write(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT); // port + // addressing + // header + bo.write(0x04); // each port is 2 octets + bo.write((destinationPort >> 8) & 0xFF); // MSB of destination port + bo.write(destinationPort & 0xFF); // LSB of destination port + bo.write(0x00); // MSB of originating port + bo.write(0x00); // LSB of originating port + + // User data + bo.write(data, 0, data.length); + + ret.encodedMessage = bo.toByteArray(); + return ret; + } + + /** + * Create the beginning of a SUBMIT PDU. This is the part of the + * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, + * one of which takes a byte array and the other of which takes a + * String. + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param mtiByte + * @param ret SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message + */ + private static ByteArrayOutputStream getSubmitPduHead( + String scAddress, String destinationAddress, byte mtiByte, + boolean statusReportRequested, SubmitPdu ret) { + ByteArrayOutputStream bo = new ByteArrayOutputStream( + MAX_USER_DATA_BYTES + 40); + + // SMSC address with length octet, or 0 + if (scAddress == null) { + ret.encodedScAddress = null; + } else { + ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( + scAddress); + } + + // TP-Message-Type-Indicator (and friends) + if (statusReportRequested) { + // Set TP-Status-Report-Request bit. + mtiByte |= 0x20; + if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested"); + } + bo.write(mtiByte); + + // space for TP-Message-Reference + bo.write(0); + + byte[] daBytes; + + daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); + + // destination address length in BCD digits, ignoring TON byte and pad + // TODO Should be better. + bo.write((daBytes.length - 1) * 2 + - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); + + // destination address + bo.write(daBytes, 0, daBytes.length); + + // TP-Protocol-Identifier + bo.write(0); + return bo; + } + + static class PduParser { + byte pdu[]; + int cur; + SmsHeader userDataHeader; + byte[] userData; + int mUserDataSeptetPadding; + int mUserDataSize; + + PduParser(String s) { + this(IccUtils.hexStringToBytes(s)); + } + + PduParser(byte[] pdu) { + this.pdu = pdu; + cur = 0; + mUserDataSeptetPadding = 0; + } + + /** + * Parse and return the SC address prepended to SMS messages coming via + * the TS 27.005 / AT interface. Returns null on invalid address + */ + String getSCAddress() { + int len; + String ret; + + // length of SC Address + len = getByte(); + + if (len == 0) { + // no SC address + ret = null; + } else { + // SC address + try { + ret = PhoneNumberUtils + .calledPartyBCDToString(pdu, cur, len); + } catch (RuntimeException tr) { + Log.d(LOG_TAG, "invalid SC address: ", tr); + ret = null; + } + } + + cur += len; + + return ret; + } + + /** + * returns non-sign-extended byte value + */ + int getByte() { + return pdu[cur++] & 0xff; + } + + /** + * Any address except the SC address (eg, originating address) See TS + * 23.040 9.1.2.5 + */ + GsmSmsAddress getAddress() { + GsmSmsAddress ret; + + // "The Address-Length field is an integer representation of + // the number field, i.e. excludes any semi octet containing only + // fill bits." + // The TOA field is not included as part of this + int addressLength = pdu[cur] & 0xff; + int lengthBytes = 2 + (addressLength + 1) / 2; + + ret = new GsmSmsAddress(pdu, cur, lengthBytes); + + cur += lengthBytes; + + return ret; + } + + /** + * Parses an SC timestamp and returns a currentTimeMillis()-style + * timestamp + */ + + long getSCTimestampMillis() { + // TP-Service-Centre-Time-Stamp + int year = IccUtils.bcdByteToInt(pdu[cur++]); + int month = IccUtils.bcdByteToInt(pdu[cur++]); + int day = IccUtils.bcdByteToInt(pdu[cur++]); + int hour = IccUtils.bcdByteToInt(pdu[cur++]); + int minute = IccUtils.bcdByteToInt(pdu[cur++]); + int second = IccUtils.bcdByteToInt(pdu[cur++]); + + // For the timezone, the most significant bit of the + // least signficant nibble is the sign byte + // (meaning the max range of this field is 79 quarter-hours, + // which is more than enough) + + byte tzByte = pdu[cur++]; + + // Mask out sign bit. + int timezoneOffset = IccUtils + .bcdByteToInt((byte) (tzByte & (~0x08))); + + timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset + : -timezoneOffset; + + Time time = new Time(Time.TIMEZONE_UTC); + + // It's 2006. Should I really support years < 2000? + time.year = year >= 90 ? year + 1900 : year + 2000; + time.month = month - 1; + time.monthDay = day; + time.hour = hour; + time.minute = minute; + time.second = second; + + // Timezone offset is in quarter hours. + return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); + } + + /** + * Pulls the user data out of the PDU, and separates the payload from + * the header if there is one. + * + * @param hasUserDataHeader true if there is a user data header + * @param dataInSeptets true if the data payload is in septets instead + * of octets + * @return the number of septets or octets in the user data payload + */ + int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) { + int offset = cur; + int userDataLength = pdu[offset++] & 0xff; + int headerSeptets = 0; + + if (hasUserDataHeader) { + int userDataHeaderLength = pdu[offset++] & 0xff; + + byte[] udh = new byte[userDataHeaderLength]; + System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); + userDataHeader = SmsHeader.parse(udh); + offset += userDataHeaderLength; + + int headerBits = (userDataHeaderLength + 1) * 8; + headerSeptets = headerBits / 7; + headerSeptets += (headerBits % 7) > 0 ? 1 : 0; + mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; + } + + /* + * Here we just create the user data length to be the remainder of + * the pdu minus the user data hearder. This is because the count + * could mean the number of uncompressed sepets if the userdata is + * encoded in 7-bit. + */ + userData = new byte[pdu.length - offset]; + System.arraycopy(pdu, offset, userData, 0, userData.length); + cur = offset; + + if (dataInSeptets) { + // Return the number of septets + return userDataLength - headerSeptets; + } else { + // Return the number of octets + return userData.length; + } + } + + /** + * Returns the user data payload, not including the headers + * + * @return the user data payload, not including the headers + */ + byte[] getUserData() { + return userData; + } + + /** + * Returns the number of padding bits at the begining of the user data + * array before the start of the septets. + * + * @return the number of padding bits at the begining of the user data + * array before the start of the septets + */ + int getUserDataSeptetPadding() { + return mUserDataSeptetPadding; + } + + /** + * Returns an object representing the user data headers + * + * @return an object representing the user data headers + * + * {@hide} + */ + SmsHeader getUserDataHeader() { + return userDataHeader; + } + +/* + XXX Not sure what this one is supposed to be doing, and no one is using + it. + String getUserDataGSM8bit() { + // System.out.println("remainder of pud:" + + // HexDump.dumpHexString(pdu, cur, pdu.length - cur)); + int count = pdu[cur++] & 0xff; + int size = pdu[cur++]; + + // skip over header for now + cur += size; + + if (pdu[cur - 1] == 0x01) { + int tid = pdu[cur++] & 0xff; + int type = pdu[cur++] & 0xff; + + size = pdu[cur++] & 0xff; + + int i = cur; + + while (pdu[i++] != '\0') { + } + + int length = i - cur; + String mimeType = new String(pdu, cur, length); + + cur += length; + + if (false) { + System.out.println("tid = 0x" + HexDump.toHexString(tid)); + System.out.println("type = 0x" + HexDump.toHexString(type)); + System.out.println("header size = " + size); + System.out.println("mimeType = " + mimeType); + System.out.println("remainder of header:" + + HexDump.dumpHexString(pdu, cur, (size - mimeType.length()))); + } + + cur += size - mimeType.length(); + + // System.out.println("data count = " + count + " cur = " + cur + // + " :" + HexDump.dumpHexString(pdu, cur, pdu.length - cur)); + + MMSMessage msg = MMSMessage.parseEncoding(mContext, pdu, cur, + pdu.length - cur); + } else { + System.out.println(new String(pdu, cur, pdu.length - cur - 1)); + } + + return IccUtils.bytesToHexString(pdu); + } +*/ + + /** + * Interprets the user data payload as pack GSM 7bit characters, and + * decodes them into a String. + * + * @param septetCount the number of septets in the user data payload + * @return a String with the decoded characters + */ + String getUserDataGSM7Bit(int septetCount) { + String ret; + + ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount, + mUserDataSeptetPadding); + + cur += (septetCount * 7) / 8; + + return ret; + } + + /** + * Interprets the user data payload as UCS2 characters, and + * decodes them into a String. + * + * @param byteCount the number of bytes in the user data payload + * @return a String with the decoded characters + */ + String getUserDataUCS2(int byteCount) { + String ret; + + try { + ret = new String(pdu, cur, byteCount, "utf-16"); + } catch (UnsupportedEncodingException ex) { + ret = ""; + Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); + } + + cur += byteCount; + return ret; + } + + boolean moreDataPresent() { + return (pdu.length > cur); + } + } + + /** {@inheritDoc} */ + public int getProtocolIdentifier() { + return protocolIdentifier; + } + + /** {@inheritDoc} */ + public boolean isReplace() { + return (protocolIdentifier & 0xc0) == 0x40 + && (protocolIdentifier & 0x3f) > 0 + && (protocolIdentifier & 0x3f) < 8; + } + + /** {@inheritDoc} */ + public boolean isCphsMwiMessage() { + return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear() + || ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); + } + + /** {@inheritDoc} */ + public boolean isMWIClearMessage() { + if (isMwi && (mwiSense == false)) { + return true; + } + + return originatingAddress != null + && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear(); + } + + /** {@inheritDoc} */ + public boolean isMWISetMessage() { + if (isMwi && (mwiSense == true)) { + return true; + } + + return originatingAddress != null + && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); + } + + /** {@inheritDoc} */ + public boolean isMwiDontStore() { + if (isMwi && mwiDontStore) { + return true; + } + + if (isCphsMwiMessage()) { + // See CPHS 4.2 Section B.4.2.1 + // If the user data is a single space char, do not store + // the message. Otherwise, store and display as usual + if (" ".equals(getMessageBody())) { + ; + } + return true; + } + + return false; + } + + /** {@inheritDoc} */ + public int getStatus() { + return status; + } + + /** {@inheritDoc} */ + public boolean isStatusReportMessage() { + return isStatusReportMessage; + } + + /** {@inheritDoc} */ + public boolean isReplyPathPresent() { + return replyPathPresent; + } + + /** + * TS 27.005 3.1, definition "In the case of SMS: 3GPP TS 24.011 [6] + * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: + * ME/TA converts each octet of TP data unit into two IRA character long + * hexad number (e.g. octet with integer value 42 is presented to TE as two + * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, + * something else... + */ + private void parsePdu(byte[] pdu) { + mPdu = pdu; + // Log.d(LOG_TAG, "raw sms mesage:"); + // Log.d(LOG_TAG, s); + + PduParser p = new PduParser(pdu); + + scAddress = p.getSCAddress(); + + if (scAddress != null) { + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC address: " + scAddress); + } + + // TODO(mkf) support reply path, user data header indicator + + // TP-Message-Type-Indicator + // 9.2.3 + int firstByte = p.getByte(); + + mti = firstByte & 0x3; + switch (mti) { + // TP-Message-Type-Indicator + // 9.2.3 + case 0: + parseSmsDeliver(p, firstByte); + break; + case 2: + parseSmsStatusReport(p, firstByte); + break; + default: + // TODO(mkf) the rest of these + throw new RuntimeException("Unsupported message type"); + } + } + + /** + * Parses a SMS-STATUS-REPORT message. + * + * @param p A PduParser, cued past the first byte. + * @param firstByte The first byte of the PDU, which contains MTI, etc. + */ + private void parseSmsStatusReport(PduParser p, int firstByte) { + isStatusReportMessage = true; + + // TP-Status-Report-Qualifier bit == 0 for SUBMIT + forSubmit = (firstByte & 0x20) == 0x00; + // TP-Message-Reference + messageRef = p.getByte(); + // TP-Recipient-Address + recipientAddress = p.getAddress(); + // TP-Service-Centre-Time-Stamp + scTimeMillis = p.getSCTimestampMillis(); + // TP-Discharge-Time + dischargeTimeMillis = p.getSCTimestampMillis(); + // TP-Status + status = p.getByte(); + + // The following are optional fields that may or may not be present. + if (p.moreDataPresent()) { + // TP-Parameter-Indicator + int extraParams = p.getByte(); + int moreExtraParams = extraParams; + while ((moreExtraParams & 0x80) != 0) { + // We only know how to parse a few extra parameters, all + // indicated in the first TP-PI octet, so skip over any + // additional TP-PI octets. + moreExtraParams = p.getByte(); + } + // TP-Protocol-Identifier + if ((extraParams & 0x01) != 0) { + protocolIdentifier = p.getByte(); + } + // TP-Data-Coding-Scheme + if ((extraParams & 0x02) != 0) { + dataCodingScheme = p.getByte(); + } + // TP-User-Data-Length (implies existence of TP-User-Data) + if ((extraParams & 0x04) != 0) { + boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; + parseUserData(p, hasUserDataHeader); + } + } + } + + private void parseSmsDeliver(PduParser p, int firstByte) { + replyPathPresent = (firstByte & 0x80) == 0x80; + + originatingAddress = p.getAddress(); + + if (originatingAddress != null) { + if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + + originatingAddress.address); + } + + // TP-Protocol-Identifier (TP-PID) + // TS 23.040 9.2.3.9 + protocolIdentifier = p.getByte(); + + // TP-Data-Coding-Scheme + // see TS 23.038 + dataCodingScheme = p.getByte(); + + if (Config.LOGV) { + Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier + + " data coding scheme: " + dataCodingScheme); + } + + scTimeMillis = p.getSCTimestampMillis(); + + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); + + boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; + + parseUserData(p, hasUserDataHeader); + } + + /** + * Parses the User Data of an SMS. + * + * @param p The current PduParser. + * @param hasUserDataHeader Indicates whether a header is present in the + * User Data. + */ + private void parseUserData(PduParser p, boolean hasUserDataHeader) { + boolean hasMessageClass = false; + boolean userDataCompressed = false; + + int encodingType = ENCODING_UNKNOWN; + + // Look up the data encoding scheme + if ((dataCodingScheme & 0x80) == 0) { + // Bits 7..4 == 0xxx + automaticDeletion = (0 != (dataCodingScheme & 0x40)); + userDataCompressed = (0 != (dataCodingScheme & 0x20)); + hasMessageClass = (0 != (dataCodingScheme & 0x10)); + + if (userDataCompressed) { + Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " + + "(compression) " + (dataCodingScheme & 0xff)); + } else { + switch ((dataCodingScheme >> 2) & 0x3) { + case 0: // GSM 7 bit default alphabet + encodingType = ENCODING_7BIT; + break; + + case 2: // UCS 2 (16bit) + encodingType = ENCODING_16BIT; + break; + + case 1: // 8 bit data + case 3: // reserved + Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " + + (dataCodingScheme & 0xff)); + encodingType = ENCODING_8BIT; + break; + } + } + } else if ((dataCodingScheme & 0xf0) == 0xf0) { + automaticDeletion = false; + hasMessageClass = true; + userDataCompressed = false; + + if (0 == (dataCodingScheme & 0x04)) { + // GSM 7 bit default alphabet + encodingType = ENCODING_7BIT; + } else { + // 8 bit data + encodingType = ENCODING_8BIT; + } + } else if ((dataCodingScheme & 0xF0) == 0xC0 + || (dataCodingScheme & 0xF0) == 0xD0 + || (dataCodingScheme & 0xF0) == 0xE0) { + // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 + + // 0xC0 == 7 bit, don't store + // 0xD0 == 7 bit, store + // 0xE0 == UCS-2, store + + if ((dataCodingScheme & 0xF0) == 0xE0) { + encodingType = ENCODING_16BIT; + } else { + encodingType = ENCODING_7BIT; + } + + userDataCompressed = false; + boolean active = ((dataCodingScheme & 0x08) == 0x08); + + // bit 0x04 reserved + + if ((dataCodingScheme & 0x03) == 0x00) { + isMwi = true; + mwiSense = active; + mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0); + } else { + isMwi = false; + + Log.w(LOG_TAG, "MWI for fax, email, or other " + + (dataCodingScheme & 0xff)); + } + } else { + Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " + + (dataCodingScheme & 0xff)); + } + + // set both the user data and the user data header. + int count = p.constructUserData(hasUserDataHeader, + encodingType == ENCODING_7BIT); + this.userData = p.getUserData(); + this.userDataHeader = p.getUserDataHeader(); + + switch (encodingType) { + case ENCODING_UNKNOWN: + case ENCODING_8BIT: + messageBody = null; + break; + + case ENCODING_7BIT: + messageBody = p.getUserDataGSM7Bit(count); + break; + + case ENCODING_16BIT: + messageBody = p.getUserDataUCS2(count); + break; + } + + if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); + + if (messageBody != null) { + parseMessageBody(); + } + + if (!hasMessageClass) { + messageClass = MessageClass.UNKNOWN; + } else { + switch (dataCodingScheme & 0x3) { + case 0: + messageClass = MessageClass.CLASS_0; + break; + case 1: + messageClass = MessageClass.CLASS_1; + break; + case 2: + messageClass = MessageClass.CLASS_2; + break; + case 3: + messageClass = MessageClass.CLASS_3; + break; + } + } + } + + /** + * {@inheritDoc} + */ + public MessageClass getMessageClass() { + return messageClass; + } + +} 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 26c2175b78ad1a3626837b8e4614b9d9e36c30a6..19d3279c35abcfdc813b6b48291d578ef9f27b6c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java @@ -20,9 +20,9 @@ import java.util.List; /** * Class for representing BER-TLV objects. - * + * * @see "ETSI TS 102 223 Annex C" for more information. - * + * * {@hide} */ class BerTlv { @@ -41,16 +41,16 @@ class BerTlv { /** * Gets a list of ComprehensionTlv objects contained in this BER-TLV object. - * + * * @return A list of COMPREHENSION-TLV object */ public List getComprehensionTlvs() { return mCompTlvs; } - + /** * Gets a tag id of the BER-TLV object. - * + * * @return A tag integer. */ public int getTag() { @@ -59,7 +59,7 @@ class BerTlv { /** * Decodes a BER-TLV object from a byte array. - * + * * @param data A byte array to decode from * @return A BER-TLV object decoded * @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 60e8148b6fe5f514937b7ae2fbeb20911168d6a2..a27c5823c2d870211a92bdecbffddf759c9d8835 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java @@ -19,7 +19,7 @@ package com.android.internal.telephony.gsm.stk; import android.graphics.Bitmap; /** - * Container class for proactive command parameters. + * Container class for proactive command parameters. * */ class CommandParams { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java index eb354e95c8ad642059dfb93451934e785c659f56..06b36a455bef85ccd9b110034fefb88e6f1ab56c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java @@ -20,7 +20,7 @@ import android.graphics.Bitmap; import android.os.Handler; import android.os.Message; -import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.gsm.SIMFileHandler; import java.util.Iterator; 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 833ff3cfffb04bf0710df437c015b0ebeb183b1f..4f746ac3e3aafada07d150ec4c3156b6fda44480 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java @@ -22,9 +22,9 @@ import java.util.List; /** * Class for representing COMPREHENSION-TLV objects. - * + * * @see "ETSI TS 101 220 subsection 7.1.1" - * + * * {@hide} */ class ComprehensionTlv { @@ -38,7 +38,7 @@ class ComprehensionTlv { * Constructor. Private on purpose. Use * {@link #decodeMany(byte[], int) decodeMany} or * {@link #decode(byte[], int) decode} method. - * + * * @param tag The tag for this object * @param cr Comprehension Required flag * @param length Length of the value @@ -76,7 +76,7 @@ class ComprehensionTlv { /** * Parses a list of COMPREHENSION-TLV objects from a byte array. - * + * * @param data A byte array containing data to be parsed * @param startIndex Index in data at which to start parsing * @return A list of COMPREHENSION-TLV objects parsed @@ -97,7 +97,7 @@ class ComprehensionTlv { /** * Parses an COMPREHENSION-TLV object from a byte array. - * + * * @param data A byte array containing data to be parsed * @param startIndex Index in data at which to start parsing * @return A COMPREHENSION-TLV object parsed 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 a63d1ca482d5eaae11e420b23833a82aa557d347..fc02d2a6c3d47ca828e4b8a0cbf2f1162b1e2ddf 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java @@ -30,9 +30,9 @@ import android.util.Log; import java.util.HashMap; /** - * Class for loading icons from the SIM card. Has two states: single, for loading + * Class for loading icons from the SIM card. Has two states: single, for loading * one icon. Multi, for loading icons list. - * + * */ class IconLoader extends Handler { // members @@ -51,13 +51,13 @@ class IconLoader extends Handler { private static IconLoader sLoader = null; - // Loader state values. + // Loader state values. private static final int STATE_SINGLE_ICON = 1; private static final int STATE_MULTI_ICONS = 2; - // Finished loading single record from a linear-fixed EF-IMG. + // Finished loading single record from a linear-fixed EF-IMG. private static final int EVENT_READ_EF_IMG_RECOED_DONE = 1; - // Finished loading single icon from a Transparent DF-Graphics. + // Finished loading single icon from a Transparent DF-Graphics. private static final int EVENT_READ_ICON_DONE = 2; // Finished loading single colour icon lookup table. private static final int EVENT_READ_CLUT_DONE = 3; @@ -170,10 +170,10 @@ class IconLoader extends Handler { } /** - * Handles Image descriptor parsing and required processing. This is the + * Handles Image descriptor parsing and required processing. This is the * first step required to handle retrieving icons from the SIM. - * - * @param data byte [] containing Image Instance descriptor as defined in + * + * @param data byte [] containing Image Instance descriptor as defined in * TS 51.011. */ private boolean handleImageDescriptor(byte[] rawData) { @@ -232,7 +232,7 @@ class IconLoader extends Handler { * @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; @@ -264,7 +264,7 @@ class IconLoader extends Handler { * 0 is black * 1 is white * @param bit to decode - * @return RGB color + * @return RGB color */ private static int bitToBnW(int bit){ if(bit == 1){ @@ -276,11 +276,11 @@ class IconLoader extends Handler { /** * 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 - * @param clut coulor lookup table + * @param clut coulor lookup table * @return The color bitmap */ public static Bitmap parseToRGB(byte[] data, int length, @@ -321,9 +321,9 @@ class IconLoader extends Handler { return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); } - + /** - * Calculate bit mask for a given number of bits. The mask should enable to + * Calculate bit mask for a given number of bits. The mask should enable to * make a bitwise and to the given number of bits. * @param numOfBits number of bits to calculate mask for. * @return bit mask diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java b/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java index 7120a379dc25fdbec593da009026b95e82011526..880b9e5c11e452ee7627a5c37f390ce39a49a91f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java @@ -33,7 +33,8 @@ public class ImageDescriptor { static final int CODING_SCHEME_BASIC = 0x11; static final int CODING_SCHEME_COLOUR = 0x21; - public static final int ID_LENGTH = 9; + // public static final int ID_LENGTH = 9; + // ID_LENGTH substituted by IccFileHandlerBase.GET_RESPONSE_EF_IMG_SIZE_BYTES ImageDescriptor() { width = 0; @@ -47,7 +48,7 @@ public class ImageDescriptor { /** * Extract descriptor information about image instance. - * + * * @param rawData * @param valueIndex * @return ImageDescriptor diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java b/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java index 9afa063891c6b30222a90ca32a19d9836edc3c63..810afd2d201ec3dcfa56b3b5bcf6edc4d18845d9 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java @@ -16,8 +16,8 @@ package com.android.internal.telephony.gsm.stk; -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java index 5d82473a265369bd124e30caf303c99d9d5849da..1cf38ed07cb7a0d41db8d85e2d7e6f2e79050819 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java @@ -17,7 +17,7 @@ package com.android.internal.telephony.gsm.stk; import com.android.internal.telephony.gsm.SIMFileHandler; -import com.android.internal.telephony.gsm.SimUtils; +import com.android.internal.telephony.IccUtils; import android.os.Handler; import android.os.HandlerState; @@ -142,7 +142,7 @@ class RilMessageDecoder extends HandlerStateMachine { case StkService.MSG_ID_REFRESH: byte[] rawData = null; try { - rawData = SimUtils.hexStringToBytes((String) rilMsg.mData); + rawData = IccUtils.hexStringToBytes((String) rilMsg.mData); } catch (Exception e) { // zombie messages are dropped StkLog.d(this, "decodeMessageParams dropping zombie messages"); diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java index c0c4ceb5c795a54aa381edcd2be98ce3d3a35f86..3de14f001491155e969db1b82dbb529d2cf32a5f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java @@ -23,11 +23,13 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Message; -import com.android.internal.telephony.gsm.CommandsInterface; -import com.android.internal.telephony.gsm.GsmSimCard; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.gsm.SimCard; import com.android.internal.telephony.gsm.SIMFileHandler; import com.android.internal.telephony.gsm.SIMRecords; -import com.android.internal.telephony.gsm.SimUtils; import android.util.Config; @@ -115,10 +117,12 @@ class RilMessage { */ public class StkService extends Handler implements AppInterface { + // Class members + private static SIMRecords mSimRecords; + // Service members. private static StkService sInstance; private CommandsInterface mCmdIf; - private SIMRecords mSimRecords; private Context mContext; private StkCmdMessage mCurrntCmd = null; private StkCmdMessage mMenuCmd = null; @@ -147,7 +151,7 @@ public class StkService extends Handler implements AppInterface { /* Intentionally private for singleton */ private StkService(CommandsInterface ci, SIMRecords sr, Context context, - SIMFileHandler fh, GsmSimCard sc) { + SIMFileHandler fh, SimCard sc) { if (ci == null || sr == null || context == null || fh == null || sc == null) { throw new NullPointerException( @@ -172,6 +176,23 @@ public class StkService extends Handler implements AppInterface { mSimRecords.registerForRecordsLoaded(this, MSG_ID_SIM_LOADED, null); } + public void dispose() { + mSimRecords.unregisterForRecordsLoaded(this); + mCmdIf.unSetOnStkSessionEnd(this); + mCmdIf.unSetOnStkProactiveCmd(this); + mCmdIf.unSetOnStkEvent(this); + mCmdIf.unSetOnStkCallSetUp(this); + + this.removeCallbacksAndMessages(null); + + //removing instance + sInstance = null; + } + + protected void finalize() { + StkLog.d(this, "Service finalized"); + } + private void handleRilMsg(RilMessage rilMsg) { if (rilMsg == null) { return; @@ -334,7 +355,7 @@ public class StkService extends Handler implements AppInterface { } byte[] rawData = buf.toByteArray(); - String hexString = SimUtils.bytesToHexString(rawData); + String hexString = IccUtils.bytesToHexString(rawData); if (Config.LOGD) { StkLog.d(this, "TERMINAL RESPONSE: " + hexString); } @@ -380,7 +401,7 @@ public class StkService extends Handler implements AppInterface { int len = rawData.length - 2; // minus (tag + length) rawData[1] = (byte) len; - String hexString = SimUtils.bytesToHexString(rawData); + String hexString = IccUtils.bytesToHexString(rawData); mCmdIf.sendEnvelope(hexString, null); } @@ -423,7 +444,7 @@ public class StkService extends Handler implements AppInterface { int len = rawData.length - 2; // minus (tag + length) rawData[1] = (byte) len; - String hexString = SimUtils.bytesToHexString(rawData); + String hexString = IccUtils.bytesToHexString(rawData); mCmdIf.sendEnvelope(hexString, null); } @@ -439,7 +460,7 @@ public class StkService extends Handler implements AppInterface { * @return The only Service object in the system */ public static StkService getInstance(CommandsInterface ci, SIMRecords sr, - Context context, SIMFileHandler fh, GsmSimCard sc) { + Context context, SIMFileHandler fh, SimCard sc) { if (sInstance == null) { if (ci == null || sr == null || context == null || fh == null || sc == null) { @@ -448,6 +469,17 @@ public class StkService extends Handler implements AppInterface { HandlerThread thread = new HandlerThread("Stk Telephony service"); thread.start(); sInstance = new StkService(ci, sr, context, fh, sc); + StkLog.d(sInstance, "NEW sInstance"); + } else if ((sr != null) && (mSimRecords != sr)) { + StkLog.d(sInstance, String.format( + "Reinitialize the Service with SIMRecords sr=0x%x.", sr)); + mSimRecords = sr; + + // re-Register for SIM ready event. + mSimRecords.registerForRecordsLoaded(sInstance, MSG_ID_SIM_LOADED, null); + StkLog.d(sInstance, "sr changed reinitialize and return current sInstance"); + } else { + StkLog.d(sInstance, "Return current sInstance"); } return sInstance; } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java b/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java index 2cf87ba715ab8488159b2b355364ea729ee74a29..8c8f977c33c42d45763a1d1e0eefdbf6e28af76d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java @@ -16,8 +16,8 @@ package com.android.internal.telephony.gsm.stk; -import com.android.internal.telephony.gsm.GsmAlphabet; -import com.android.internal.telephony.gsm.SimUtils; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.gsm.stk.Duration.TimeUnit; import java.io.UnsupportedEncodingException; @@ -117,7 +117,7 @@ abstract class ValueParser { try { int id = rawValue[valueIndex] & 0xff; - String text = SimUtils.adnStringFieldToString(rawValue, + String text = IccUtils.adnStringFieldToString(rawValue, valueIndex + 1, textLen); item = new Item(id, text); } catch (IndexOutOfBoundsException e) { @@ -278,7 +278,7 @@ abstract class ValueParser { int length = ctlv.getLength(); if (length != 0) { try { - return SimUtils.adnStringFieldToString(rawValue, valueIndex, + return IccUtils.adnStringFieldToString(rawValue, valueIndex, length); } catch (IndexOutOfBoundsException e) { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 33c167953e05b27fdba0381c8cf5ddaf1c451212..5c69017e037988776d2a5375e47cbd85b0d9ff1f 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -23,19 +23,18 @@ import android.os.Looper; import android.os.Message; import android.util.Log; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.BaseCommands; +import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; 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.PDPContextState; import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.Phone; import java.util.ArrayList; public final class SimulatedCommands extends BaseCommands - implements CommandsInterface, SimulatedRadioControl -{ + implements CommandsInterface, SimulatedRadioControl { private final static String LOG_TAG = "SIM"; private enum SimLockState { @@ -43,14 +42,14 @@ public final class SimulatedCommands extends BaseCommands REQUIRE_PIN, REQUIRE_PUK, SIM_PERM_LOCKED - }; + } private enum SimFdnState { NONE, REQUIRE_PIN2, REQUIRE_PUK2, SIM_PERM_LOCKED - }; + } private final static SimLockState INITIAL_LOCK_STATE = SimLockState.NONE; private final static String DEFAULT_SIM_PIN_CODE = "1234"; @@ -103,11 +102,10 @@ public final class SimulatedCommands extends BaseCommands //***** CommandsInterface implementation - public void getSimStatus(Message result) - { + public void getIccStatus(Message result) { switch (mState) { case SIM_READY: - resultSuccess(result, SimStatus.SIM_READY); + resultSuccess(result, IccStatus.ICC_READY); break; case SIM_LOCKED_OR_ABSENT: @@ -115,7 +113,7 @@ public final class SimulatedCommands extends BaseCommands break; default: - resultSuccess(result, SimStatus.SIM_NOT_READY); + resultSuccess(result, IccStatus.ICC_NOT_READY); break; } } @@ -123,13 +121,13 @@ public final class SimulatedCommands extends BaseCommands private void returnSimLockedStatus(Message result) { switch (mSimLockedState) { case REQUIRE_PIN: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: SIM_PIN"); - resultSuccess(result, SimStatus.SIM_PIN); + Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PIN"); + resultSuccess(result, IccStatus.ICC_PIN); break; case REQUIRE_PUK: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: SIM_PUK"); - resultSuccess(result, SimStatus.SIM_PUK); + Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PUK"); + resultSuccess(result, IccStatus.ICC_PUK); break; default: @@ -139,9 +137,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPin(String pin, Message result) { + public void supplyIccPin(String pin, Message result) { if (mSimLockedState != SimLockState.REQUIRE_PIN) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: wrong state, state=" + mSimLockedState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -151,7 +149,7 @@ public final class SimulatedCommands extends BaseCommands } if (pin != null && pin.equals(mPinCode)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: success!"); setRadioState(RadioState.SIM_READY); mPinUnlockAttempts = 0; mSimLockedState = SimLockState.NONE; @@ -167,10 +165,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPinUnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPin: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: failed! attempt=" + mPinUnlockAttempts); if (mPinUnlockAttempts >= 3) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin: set state to REQUIRE_PUK"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin: set state to REQUIRE_PUK"); mSimLockedState = SimLockState.REQUIRE_PUK; } @@ -181,9 +179,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPuk(String puk, String newPin, Message result) { + public void supplyIccPuk(String puk, String newPin, Message result) { if (mSimLockedState != SimLockState.REQUIRE_PUK) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: wrong state, state=" + mSimLockedState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -193,7 +191,7 @@ public final class SimulatedCommands extends BaseCommands } if (puk != null && puk.equals(SIM_PUK_CODE)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: success!"); setRadioState(RadioState.SIM_READY); mSimLockedState = SimLockState.NONE; mPukUnlockAttempts = 0; @@ -209,10 +207,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPukUnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: failed! attempt=" + mPukUnlockAttempts); if (mPukUnlockAttempts >= 10) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk: set state to SIM_PERM_LOCKED"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk: set state to SIM_PERM_LOCKED"); mSimLockedState = SimLockState.SIM_PERM_LOCKED; } @@ -223,9 +221,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPin2(String pin2, Message result) { + public void supplyIccPin2(String pin2, Message result) { if (mSimFdnEnabledState != SimFdnState.REQUIRE_PIN2) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: wrong state, state=" + mSimFdnEnabledState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -235,7 +233,7 @@ public final class SimulatedCommands extends BaseCommands } if (pin2 != null && pin2.equals(mPin2Code)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: success!"); mPin2UnlockAttempts = 0; mSimFdnEnabledState = SimFdnState.NONE; @@ -250,10 +248,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPin2UnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: failed! attempt=" + mPin2UnlockAttempts); if (mPin2UnlockAttempts >= 3) { - Log.i(LOG_TAG, "[SimCmd] supplySimPin2: set state to REQUIRE_PUK2"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPin2: set state to REQUIRE_PUK2"); mSimFdnEnabledState = SimFdnState.REQUIRE_PUK2; } @@ -264,9 +262,9 @@ public final class SimulatedCommands extends BaseCommands } } - public void supplySimPuk2(String puk2, String newPin2, Message result) { + public void supplyIccPuk2(String puk2, String newPin2, Message result) { if (mSimFdnEnabledState != SimFdnState.REQUIRE_PUK2) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: wrong state, state=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: wrong state, state=" + mSimLockedState); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -276,7 +274,7 @@ public final class SimulatedCommands extends BaseCommands } if (puk2 != null && puk2.equals(SIM_PUK2_CODE)) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: success!"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: success!"); mSimFdnEnabledState = SimFdnState.NONE; mPuk2UnlockAttempts = 0; @@ -291,10 +289,10 @@ public final class SimulatedCommands extends BaseCommands if (result != null) { mPuk2UnlockAttempts ++; - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: failed! attempt=" + + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: failed! attempt=" + mPuk2UnlockAttempts); if (mPuk2UnlockAttempts >= 10) { - Log.i(LOG_TAG, "[SimCmd] supplySimPuk2: set state to SIM_PERM_LOCKED"); + Log.i(LOG_TAG, "[SimCmd] supplyIccPuk2: set state to SIM_PERM_LOCKED"); mSimFdnEnabledState = SimFdnState.SIM_PERM_LOCKED; } @@ -305,7 +303,7 @@ public final class SimulatedCommands extends BaseCommands } } - public void changeSimPin(String oldPin, String newPin, Message result) { + public void changeIccPin(String oldPin, String newPin, Message result) { if (oldPin != null && oldPin.equals(mPinCode)) { mPinCode = newPin; if (result != null) { @@ -317,7 +315,7 @@ public final class SimulatedCommands extends BaseCommands } if (result != null) { - Log.i(LOG_TAG, "[SimCmd] changeSimPin: pin failed!"); + Log.i(LOG_TAG, "[SimCmd] changeIccPin: pin failed!"); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -326,7 +324,7 @@ public final class SimulatedCommands extends BaseCommands } } - public void changeSimPin2(String oldPin2, String newPin2, Message result) { + public void changeIccPin2(String oldPin2, String newPin2, Message result) { if (oldPin2 != null && oldPin2.equals(mPin2Code)) { mPin2Code = newPin2; if (result != null) { @@ -338,7 +336,7 @@ public final class SimulatedCommands extends BaseCommands } if (result != null) { - Log.i(LOG_TAG, "[SimCmd] changeSimPin: pin2 failed!"); + Log.i(LOG_TAG, "[SimCmd] changeIccPin2: pin2 failed!"); CommandException ex = new CommandException( CommandException.Error.PASSWORD_INCORRECT); @@ -348,14 +346,12 @@ public final class SimulatedCommands extends BaseCommands } public void - changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) - { + changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) { unimplemented(result); } public void - setSuppServiceNotifications(boolean enable, Message result) - { + setSuppServiceNotifications(boolean enable, Message result) { resultSuccess(result, null); if (enable && mSsnNotifyOn) { @@ -477,8 +473,7 @@ public final class SimulatedCommands extends BaseCommands * ar.result contains a List of DriverCall * The ar.result List is sorted by DriverCall.index */ - public void getCurrentCalls (Message result) - { + public void getCurrentCalls (Message result) { if (mState == RadioState.SIM_READY) { //Log.i("GSM", "[SimCmds] getCurrentCalls"); resultSuccess(result, simulatedCallState.getDriverCalls()); @@ -491,14 +486,20 @@ public final class SimulatedCommands extends BaseCommands } /** + * @deprecated + */ + public void getPDPContextList(Message result) { + getDataCallList(result); + } + + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result contains a List of PDPContextState */ - public void getPDPContextList(Message result) - { + public void getDataCallList(Message result) { resultSuccess(result, new ArrayList(0)); } @@ -513,8 +514,7 @@ public final class SimulatedCommands extends BaseCommands * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation) * CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation) */ - public void dial (String address, int clirMode, Message result) - { + public void dial (String address, int clirMode, Message result) { simulatedCallState.onDial(address); resultSuccess(result, null); @@ -527,8 +527,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is String containing IMSI on success */ - public void getIMSI(Message result) - { + public void getIMSI(Message result) { resultSuccess(result, "012345678901234"); } @@ -539,8 +538,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is String containing IMEI on success */ - public void getIMEI(Message result) - { + public void getIMEI(Message result) { resultSuccess(result, "012345678901234"); } @@ -551,8 +549,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is String containing IMEISV on success */ - public void getIMEISV(Message result) - { + public void getIMEISV(Message result) { resultSuccess(result, "99"); } @@ -567,8 +564,7 @@ public final class SimulatedCommands extends BaseCommands * 3GPP 22.030 6.5.5 * "Releases a specific active call X" */ - public void hangupConnection (int gsmIndex, Message result) - { + public void hangupConnection (int gsmIndex, Message result) { boolean success; success = simulatedCallState.onChld('1', (char)('0'+gsmIndex)); @@ -590,8 +586,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void hangupWaitingOrBackground (Message result) - { + public void hangupWaitingOrBackground (Message result) { boolean success; success = simulatedCallState.onChld('0', '\0'); @@ -612,8 +607,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void hangupForegroundResumeBackground (Message result) - { + public void hangupForegroundResumeBackground (Message result) { boolean success; success = simulatedCallState.onChld('1', '\0'); @@ -634,8 +628,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void switchWaitingOrHoldingAndActive (Message result) - { + public void switchWaitingOrHoldingAndActive (Message result) { boolean success; success = simulatedCallState.onChld('2', '\0'); @@ -655,8 +648,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void conference (Message result) - { + public void conference (Message result) { boolean success; success = simulatedCallState.onChld('3', '\0'); @@ -676,8 +668,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void explicitCallTransfer (Message result) - { + public void explicitCallTransfer (Message result) { boolean success; success = simulatedCallState.onChld('4', '\0'); @@ -694,8 +685,7 @@ public final class SimulatedCommands extends BaseCommands * "Places all active calls on hold except call X with which * communication shall be supported." */ - public void separateConnection (int gsmIndex, Message result) - { + public void separateConnection (int gsmIndex, Message result) { boolean success; char ch = (char)(gsmIndex + '0'); @@ -714,8 +704,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void acceptCall (Message result) - { + public void acceptCall (Message result) { boolean success; success = simulatedCallState.onAnswer(); @@ -733,8 +722,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void rejectCall (Message result) - { + public void rejectCall (Message result) { boolean success; success = simulatedCallState.onChld('0', '\0'); @@ -754,17 +742,22 @@ public final class SimulatedCommands extends BaseCommands * - Any defined in 22.001 F.4 (for generating busy/congestion) * - Cause 68: ACM >= ACMMax */ - public void getLastCallFailCause (Message result) - { + public void getLastCallFailCause (Message result) { int[] ret = new int[1]; ret[0] = nextCallFailCause; resultSuccess(result, ret); } - public void - getLastPdpFailCause (Message result) - { + /** + * @deprecated + */ + public void getLastPdpFailCause (Message result) { + unimplemented(result); + } + + public void getLastDataCallFailCause(Message result) { + // unimplemented(result); } @@ -779,8 +772,7 @@ public final class SimulatedCommands extends BaseCommands * response.obj.result[1] is bit error rate (0-7, 99) * as defined in TS 27.007 8.5 */ - public void getSignalStrength (Message result) - { + public void getSignalStrength (Message result) { int ret[] = new int[2]; ret[0] = 23; @@ -840,23 +832,30 @@ public final class SimulatedCommands extends BaseCommands } /** - * response.obj.result is an String[3] - * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2 - * response.obj.result[1] is LAC if registered or NULL if not - * response.obj.result[2] is CID if registered or NULL if not - * valid LAC are 0x0000 - 0xffff - * valid CID are 0x00000000 - 0xffffffff + * response.obj.result is an String[14] + * See ril.h for details * * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ - public void getRegistrationState (Message result) - { - String ret[] = new String[3]; + public void getRegistrationState (Message result) { + String ret[] = new String[14]; ret[0] = "5"; // registered roam ret[1] = null; ret[2] = null; + ret[3] = null; + ret[4] = null; + ret[5] = null; + ret[6] = null; + ret[7] = null; + ret[8] = null; + ret[9] = null; + ret[10] = null; + ret[11] = null; + ret[12] = null; + ret[13] = null; + ret[14] = null; resultSuccess(result, ret); } @@ -878,8 +877,7 @@ public final class SimulatedCommands extends BaseCommands * Please note that registration state 4 ("unknown") is treated * as "out of service" in the Android telephony system */ - public void getGPRSRegistrationState (Message result) - { + public void getGPRSRegistrationState (Message result) { String ret[] = new String[4]; ret[0] = "5"; // registered roam @@ -896,8 +894,7 @@ public final class SimulatedCommands extends BaseCommands * response.obj.result[1] is short alpha or null if unregistered * response.obj.result[2] is numeric or null if unregistered */ - public void getOperator(Message result) - { + public void getOperator(Message result) { String[] ret = new String[3]; ret[0] = "El Telco Loco"; @@ -912,8 +909,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void sendDtmf(char c, Message result) - { + public void sendDtmf(char c, Message result) { resultSuccess(result, null); } @@ -922,8 +918,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void startDtmf(char c, Message result) - { + public void startDtmf(char c, Message result) { resultSuccess(result, null); } @@ -932,8 +927,7 @@ public final class SimulatedCommands extends BaseCommands * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure */ - public void stopDtmf(Message result) - { + public void stopDtmf(Message result) { resultSuccess(result, null); } @@ -950,16 +944,35 @@ public final class SimulatedCommands extends BaseCommands unimplemented(response); } + public void deleteSmsOnRuim(int index, Message response) { + Log.d(LOG_TAG, "Delete RUIM message at index " + index); + unimplemented(response); + } + public void writeSmsToSim(int status, String smsc, String pdu, Message response) { Log.d(LOG_TAG, "Write SMS to SIM with status " + status); unimplemented(response); } + public void writeSmsToRuim(int status, String pdu, Message response) { + Log.d(LOG_TAG, "Write SMS to RUIM with status " + status); + unimplemented(response); + } public void setupDefaultPDP(String apn, String user, String password, Message result) { unimplemented(result); } + public void setupDataCall(String radioTechnology, String profile, String apn, String user, + String password, Message result) { + unimplemented(result); + } + + public void deactivateDataCall(int cid, Message result) {unimplemented(result);} + + /** + * @deprecated + */ public void deactivateDefaultPDP(int cid, Message result) {unimplemented(result);} public void setPreferredNetworkType(int networkType , Message result) { @@ -988,15 +1001,22 @@ public final class SimulatedCommands extends BaseCommands unimplemented(response); } + public void getSmscAddress(Message result) { + unimplemented(result); + } + + public void setSmscAddress(String address, Message result) { + unimplemented(result); + } + private boolean isSimLocked() { if (mSimLockedState != SimLockState.NONE) { return true; } return false; } - - public void setRadioPower(boolean on, Message result) - { + + public void setRadioPower(boolean on, Message result) { if(on) { if (isSimLocked()) { Log.i("SIM", "[SimCmd] setRadioPower: SIM locked! state=" + @@ -1016,12 +1036,16 @@ public final class SimulatedCommands extends BaseCommands unimplemented(result); } + public void acknowledgeLastIncomingCdmaSms(boolean success, Message result) { + unimplemented(result); + } + /** * parameters equivilient to 27.007 AT+CRSM command * response.obj will be an AsyncResult * response.obj.userObj will be a SimIoResult on success */ - public void simIO (int command, int fileid, String path, int p1, int p2, + public void iccIO (int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, Message result) { unimplemented(result); } @@ -1069,8 +1093,7 @@ public final class SimulatedCommands extends BaseCommands * @param response is callback message */ - public void queryCallWaiting(int serviceClass, Message response) - { + public void queryCallWaiting(int serviceClass, Message response) { unimplemented(response); } @@ -1081,8 +1104,7 @@ public final class SimulatedCommands extends BaseCommands */ public void setCallWaiting(boolean enable, int serviceClass, - Message response) - { + Message response) { unimplemented(response); } @@ -1092,7 +1114,7 @@ public final class SimulatedCommands extends BaseCommands * @param serviceClass is a sum of SERVICE_CLASSS_* */ public void setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message result) {unimplemented(result);} + String number, int timeSeconds, Message result) {unimplemented(result);} /** * cfReason is one of CF_REASON_* @@ -1103,11 +1125,12 @@ public final class SimulatedCommands extends BaseCommands * An array of length 0 means "disabled for all codes" */ public void queryCallForwardStatus(int cfReason, int serviceClass, - String number, Message result) {unimplemented(result);} + String number, Message result) {unimplemented(result);} public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);} - public void setNetworkSelectionModeManual(String operatorNumeric, Message result) {unimplemented(result);} + public void setNetworkSelectionModeManual( + String operatorNumeric, Message result) {unimplemented(result);} /** * Queries whether the current network selection mode is automatic @@ -1117,8 +1140,7 @@ public final class SimulatedCommands extends BaseCommands * a 0 for automatic selection and a 1 for manual selection */ - public void getNetworkSelectionMode(Message result) - { + public void getNetworkSelectionMode(Message result) { int ret[] = new int[1]; ret[0] = 0; @@ -1132,8 +1154,7 @@ public final class SimulatedCommands extends BaseCommands */ public void getAvailableNetworks(Message result) {unimplemented(result);} - public void getBasebandVersion (Message result) - { + public void getBasebandVersion (Message result) { resultSuccess(result, "SimulatedCommands"); } @@ -1172,13 +1193,11 @@ public final class SimulatedCommands extends BaseCommands } - public void resetRadio(Message result) - { + public void resetRadio(Message result) { unimplemented(result); } - public void invokeOemRilRequestRaw(byte[] data, Message response) - { + public void invokeOemRilRequestRaw(byte[] data, Message response) { // Just echo back data if (response != null) { AsyncResult.forMessage(response).result = data; @@ -1186,8 +1205,7 @@ public final class SimulatedCommands extends BaseCommands } } - public void invokeOemRilRequestStrings(String[] strings, Message response) - { + public void invokeOemRilRequestStrings(String[] strings, Message response) { // Just echo back data if (response != null) { AsyncResult.forMessage(response).result = strings; @@ -1200,23 +1218,20 @@ public final class SimulatedCommands extends BaseCommands /** Start the simulated phone ringing */ public void - triggerRing(String number) - { + triggerRing(String number) { simulatedCallState.triggerRing(number); mCallStateRegistrants.notifyRegistrants(); } public void - progressConnectingCallState() - { + progressConnectingCallState() { simulatedCallState.progressConnectingCallState(); mCallStateRegistrants.notifyRegistrants(); } /** If a call is DIALING or ALERTING, progress it all the way to ACTIVE */ public void - progressConnectingToActive() - { + progressConnectingToActive() { simulatedCallState.progressConnectingToActive(); mCallStateRegistrants.notifyRegistrants(); } @@ -1225,40 +1240,34 @@ public final class SimulatedCommands extends BaseCommands * default to true */ public void - setAutoProgressConnectingCall(boolean b) - { + setAutoProgressConnectingCall(boolean b) { simulatedCallState.setAutoProgressConnectingCall(b); } public void - setNextDialFailImmediately(boolean b) - { + setNextDialFailImmediately(boolean b) { simulatedCallState.setNextDialFailImmediately(b); } public void - setNextCallFailCause(int gsmCause) - { + setNextCallFailCause(int gsmCause) { nextCallFailCause = gsmCause; } public void - triggerHangupForeground() - { + triggerHangupForeground() { simulatedCallState.triggerHangupForeground(); mCallStateRegistrants.notifyRegistrants(); } /** hangup holding calls */ public void - triggerHangupBackground() - { + triggerHangupBackground() { simulatedCallState.triggerHangupBackground(); mCallStateRegistrants.notifyRegistrants(); } - public void triggerSsn(int type, int code) - { + public void triggerSsn(int type, int code) { SuppServiceNotification not = new SuppServiceNotification(); not.notificationType = type; not.code = code; @@ -1266,8 +1275,7 @@ public final class SimulatedCommands extends BaseCommands } public void - shutdown() - { + shutdown() { setRadioState(RadioState.RADIO_UNAVAILABLE); Looper looper = mHandlerThread.getLooper(); if (looper != null) { @@ -1278,27 +1286,23 @@ public final class SimulatedCommands extends BaseCommands /** hangup all */ public void - triggerHangupAll() - { + triggerHangupAll() { simulatedCallState.triggerHangupAll(); mCallStateRegistrants.notifyRegistrants(); } public void - triggerIncomingSMS(String message) - { + triggerIncomingSMS(String message) { //TODO } public void - pauseResponses() - { + pauseResponses() { pausedResponseCount++; } public void - resumeResponses() - { + resumeResponses() { pausedResponseCount--; if (pausedResponseCount == 0) { @@ -1313,8 +1317,7 @@ public final class SimulatedCommands extends BaseCommands //***** Private Methods - private void unimplemented(Message result) - { + private void unimplemented(Message result) { if (result != null) { AsyncResult.forMessage(result).exception = new RuntimeException("Unimplemented"); @@ -1327,8 +1330,7 @@ public final class SimulatedCommands extends BaseCommands } } - private void resultSuccess(Message result, Object ret) - { + private void resultSuccess(Message result, Object ret) { if (result != null) { AsyncResult.forMessage(result).result = ret; if (pausedResponseCount > 0) { @@ -1339,8 +1341,7 @@ public final class SimulatedCommands extends BaseCommands } } - private void resultFail(Message result, Throwable tr) - { + private void resultFail(Message result, Throwable tr) { if (result != null) { AsyncResult.forMessage(result).exception = tr; if (pausedResponseCount > 0) { @@ -1351,4 +1352,103 @@ public final class SimulatedCommands extends BaseCommands } } + // ***** Methods for CDMA support + public void + getDeviceIdentity(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void + getCDMASubscription(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void + setCdmaSubscription(int cdmaSubscriptionType, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void queryCdmaRoamingPreference(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + public void + setPhoneType(int phoneType) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + } + + public void getPreferredVoicePrivacy(Message result) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(result); + } + + public void setPreferredVoicePrivacy(boolean enable, Message result) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(result); + } + + /** + * Set the TTY mode for the CDMA phone + * + * @param enable is true to enable, false to disable + * @param serviceClass is a sum of SERVICE_CLASS_* + * @param response is callback message + */ + public void setTTYModeEnabled(boolean enable, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + /** + * Query the TTY mode for the CDMA phone + * (AsyncResult)response.obj).result is an int[] with element [0] set to + * 0 for disabled, 1 for enabled. + * + * @param serviceClass is a sum of SERVICE_CLASS_* + * @param response is callback message + */ + public void queryTTYModeEnabled(Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + /** + * {@inheritDoc} + */ + public void sendCDMAFeatureCode(String FeatureCode, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + /** + * {@inheritDoc} + */ + public void sendCdmaSms(byte[] pdu, Message response){ + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + } + + public void activateCdmaBroadcastSms(int activate, Message result) { + // TODO Auto-generated method stub + + } + + public void getCdmaBroadcastConfig(Message result) { + // TODO Auto-generated method stub + + } + + public void setCdmaBroadcastConfig(int[] configValuesArray, Message result) { + // TODO Auto-generated method stub + + } + } diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java index 340d788ac861dda2acfa0085535416dc54cb134e..803735c5464cce8ba4c4d4958350758248a2d2ae 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java @@ -21,14 +21,13 @@ import android.os.Message; import android.os.Handler; import android.telephony.PhoneNumberUtils; import com.android.internal.telephony.ATParseEx; -import com.android.internal.telephony.gsm.DriverCall; +import com.android.internal.telephony.DriverCall; import java.util.List; import java.util.ArrayList; import android.util.Log; -class CallInfo -{ +class CallInfo { enum State { ACTIVE(0), HOLDING(1), @@ -49,8 +48,7 @@ class CallInfo String number; int TOA; - CallInfo (boolean isMT, State state, boolean isMpty, String number) - { + CallInfo (boolean isMT, State state, boolean isMpty, String number) { this.isMT = isMT; this.state = state; this.isMpty = isMpty; @@ -64,20 +62,17 @@ class CallInfo } static CallInfo - createOutgoingCall(String number) - { + createOutgoingCall(String number) { return new CallInfo (false, State.DIALING, false, number); } static CallInfo - createIncomingCall(String number) - { + createIncomingCall(String number) { return new CallInfo (true, State.INCOMING, false, number); } String - toCLCCLine(int index) - { + toCLCCLine(int index) { return "+CLCC: " + index + "," + (isMT ? "1" : "0") +"," @@ -86,8 +81,7 @@ class CallInfo } DriverCall - toDriverCall(int index) - { + toDriverCall(int index) { DriverCall ret; ret = new DriverCall(); @@ -112,36 +106,30 @@ class CallInfo boolean - isActiveOrHeld() - { + isActiveOrHeld() { return state == State.ACTIVE || state == State.HOLDING; } boolean - isConnecting() - { + isConnecting() { return state == State.DIALING || state == State.ALERTING; } boolean - isRinging() - { + isRinging() { return state == State.INCOMING || state == State.WAITING; } } -class InvalidStateEx extends Exception -{ - InvalidStateEx() - { +class InvalidStateEx extends Exception { + InvalidStateEx() { } } -class SimulatedGsmCallState extends Handler -{ +class SimulatedGsmCallState extends Handler { //***** Instance Variables CallInfo calls[] = new CallInfo[MAX_CALLS]; @@ -168,8 +156,7 @@ class SimulatedGsmCallState extends Handler } public void - handleMessage(Message msg) - { + handleMessage(Message msg) { synchronized(this) { switch (msg.what) { // PLEASE REMEMBER // calls may have hung up by the time delayed events happen @@ -181,15 +168,13 @@ class SimulatedGsmCallState extends Handler } //***** Public Methods - - + /** * Start the simulated phone ringing * true if succeeded, false if failed */ public boolean - triggerRing(String number) - { + triggerRing(String number) { synchronized (this) { int empty = -1; boolean isCallWaiting = false; @@ -230,8 +215,7 @@ class SimulatedGsmCallState extends Handler /** If a call is DIALING or ALERTING, progress it to the next state */ public void - progressConnectingCallState() - { + progressConnectingCallState() { synchronized (this) { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; @@ -257,8 +241,7 @@ class SimulatedGsmCallState extends Handler /** If a call is DIALING or ALERTING, progress it all the way to ACTIVE */ public void - progressConnectingToActive() - { + progressConnectingToActive() { synchronized (this) { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; @@ -277,14 +260,12 @@ class SimulatedGsmCallState extends Handler * default to true */ public void - setAutoProgressConnectingCall(boolean b) - { + setAutoProgressConnectingCall(boolean b) { autoProgressConnecting = b; } public void - setNextDialFailImmediately(boolean b) - { + setNextDialFailImmediately(boolean b) { nextDialFailImmediately = b; } @@ -293,8 +274,7 @@ class SimulatedGsmCallState extends Handler * returns true if call was hung up, false if not */ public boolean - triggerHangupForeground() - { + triggerHangupForeground() { synchronized (this) { boolean found; @@ -333,8 +313,7 @@ class SimulatedGsmCallState extends Handler * returns true if call was hung up, false if not */ public boolean - triggerHangupBackground() - { + triggerHangupBackground() { synchronized (this) { boolean found = false; @@ -356,8 +335,7 @@ class SimulatedGsmCallState extends Handler * returns true if call was hung up, false if not */ public boolean - triggerHangupAll() - { + triggerHangupAll() { synchronized(this) { boolean found = false; @@ -376,8 +354,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onAnswer() - { + onAnswer() { synchronized (this) { for (int i = 0 ; i < calls.length ; i++) { CallInfo call = calls[i]; @@ -395,8 +372,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onHangup() - { + onHangup() { boolean found = false; for (int i = 0 ; i < calls.length ; i++) { @@ -412,8 +388,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onChld(char c0, char c1) - { + onChld(char c0, char c1) { boolean ret; int callIndex = 0; @@ -499,8 +474,7 @@ class SimulatedGsmCallState extends Handler public boolean - releaseActiveAcceptHeldOrWaiting() - { + releaseActiveAcceptHeldOrWaiting() { boolean foundHeld = false; boolean foundActive = false; @@ -555,8 +529,7 @@ class SimulatedGsmCallState extends Handler } public boolean - switchActiveAndHeldOrWaiting() - { + switchActiveAndHeldOrWaiting() { boolean hasHeld = false; // first, are there held calls? @@ -589,8 +562,7 @@ class SimulatedGsmCallState extends Handler public boolean - separateCall(int index) - { + separateCall(int index) { try { CallInfo c; @@ -631,8 +603,7 @@ class SimulatedGsmCallState extends Handler public boolean - conference() - { + conference() { int countCalls = 0; // if there's connecting calls, we can't do this yet @@ -662,8 +633,7 @@ class SimulatedGsmCallState extends Handler } public boolean - explicitCallTransfer() - { + explicitCallTransfer() { int countCalls = 0; // if there's connecting calls, we can't do this yet @@ -684,8 +654,7 @@ class SimulatedGsmCallState extends Handler } public boolean - onDial(String address) - { + onDial(String address) { CallInfo call; int freeSlot = -1; @@ -758,8 +727,7 @@ class SimulatedGsmCallState extends Handler } public List - getDriverCalls() - { + getDriverCalls() { ArrayList ret = new ArrayList(calls.length); for (int i = 0 ; i < calls.length ; i++) { @@ -779,8 +747,7 @@ class SimulatedGsmCallState extends Handler } public List - getClccLines() - { + getClccLines() { ArrayList ret = new ArrayList(calls.length); for (int i = 0 ; i < calls.length ; i++) { @@ -795,8 +762,7 @@ class SimulatedGsmCallState extends Handler } private int - countActiveLines() throws InvalidStateEx - { + countActiveLines() throws InvalidStateEx { boolean hasMpty = false; boolean hasHeld = false; boolean hasActive = false; diff --git a/test-runner/android/test/ActivityInstrumentationTestCase.java b/test-runner/android/test/ActivityInstrumentationTestCase.java index e5a9991ae557140a31114f641605bfe524108330..f6b31ad208f7d9bd0e9f1e2e581b8883f374d1e7 100644 --- a/test-runner/android/test/ActivityInstrumentationTestCase.java +++ b/test-runner/android/test/ActivityInstrumentationTestCase.java @@ -40,7 +40,11 @@ public abstract class ActivityInstrumentationTestCase boolean mInitialTouchMode = false; /** - * @param pkg The package of the instrumentation. + * NOTE: The parameter pkg must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. */ public ActivityInstrumentationTestCase(String pkg, Class activityClass) { @@ -48,7 +52,11 @@ public abstract class ActivityInstrumentationTestCase } /** - * @param pkg The package of the instrumentation. + * NOTE: The parameter pkg must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. * @param initialTouchMode true = in touch mode */ diff --git a/test-runner/android/test/ActivityInstrumentationTestCase2.java b/test-runner/android/test/ActivityInstrumentationTestCase2.java index 7a84ecae7b38834d1ad551d282f2ab43a9327cd0..679f6346537b94e05eafb302992f6472ec22fb87 100644 --- a/test-runner/android/test/ActivityInstrumentationTestCase2.java +++ b/test-runner/android/test/ActivityInstrumentationTestCase2.java @@ -46,7 +46,11 @@ public abstract class ActivityInstrumentationTestCase2 Intent mActivityIntent = null; /** - * @param pkg The package of the instrumentation. + * NOTE: The parameter pkg must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. */ public ActivityInstrumentationTestCase2(String pkg, Class activityClass) { diff --git a/test-runner/android/test/InstrumentationCoreTestRunner.java b/test-runner/android/test/InstrumentationCoreTestRunner.java index 3f77a60732bc109b2587cbf850b77fead8afda16..ff99a74930fa2d5628d55f809aee2c88029e5366 100644 --- a/test-runner/android/test/InstrumentationCoreTestRunner.java +++ b/test-runner/android/test/InstrumentationCoreTestRunner.java @@ -49,7 +49,15 @@ import android.util.Log; */ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { + /** + * Convenience definition of our log tag. + */ private static final String TAG = "InstrumentationCoreTestRunner"; + + /** + * True if (and only if) we are running in single-test mode (as opposed to + * batch mode). + */ private boolean singleTest = false; @Override @@ -57,6 +65,7 @@ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { // We might want to move this to /sdcard, if is is mounted/writable. File cacheDir = getTargetContext().getCacheDir(); + // Set some properties that the core tests absolutely need. System.setProperty("user.language", "en"); System.setProperty("user.region", "US"); @@ -74,38 +83,66 @@ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { super.onCreate(arguments); } + @Override protected AndroidTestRunner getAndroidTestRunner() { AndroidTestRunner runner = super.getAndroidTestRunner(); runner.addTestListener(new TestListener() { + /** + * The last test class we executed code from. + */ private Class lastClass; + /** + * The minimum time we expect a test to take. + */ + private static final int MINIMUM_TIME = 100; + + /** + * The start time of our current test in System.currentTimeMillis(). + */ + private long startTime; + public void startTest(Test test) { if (test.getClass() != lastClass) { + lastClass = test.getClass(); printMemory(test.getClass()); } Thread.currentThread().setContextClassLoader( test.getClass().getClassLoader()); + + startTime = System.currentTimeMillis(); } public void endTest(Test test) { if (test instanceof TestCase) { - if (lastClass == null) { - lastClass = test.getClass(); - } else { - if (test.getClass() != lastClass) { - cleanup(lastClass); - lastClass = test.getClass(); + cleanup((TestCase)test); + + /* + * Make sure all tests take at least MINIMUM_TIME to + * complete. If they don't, we wait a bit. The Cupcake + * Binder can't handle too many operations in a very + * short time, which causes headache for the CTS. + */ + long timeTaken = System.currentTimeMillis() - startTime; + + if (timeTaken < MINIMUM_TIME) { + try { + Thread.sleep(MINIMUM_TIME - timeTaken); + } catch (InterruptedException ignored) { + // We don't care. } } } } public void addError(Test test, Throwable t) { + // This space intentionally left blank. } public void addFailure(Test test, AssertionFailedError t) { + // This space intentionally left blank. } /** @@ -125,30 +162,31 @@ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { } /** - * Nulls all static reference fields in the given test class. This - * method helps us with those test classes that don't have an + * Nulls all non-static reference fields in the given test class. + * This method helps us with those test classes that don't have an * explicit tearDown() method. Normally the garbage collector should * take care of everything, but since JUnit keeps references to all * test cases, a little help might be a good idea. */ - private void cleanup(Class clazz) { - if (clazz != TestCase.class) { + private void cleanup(TestCase test) { + Class clazz = test.getClass(); + + while (clazz != TestCase.class) { Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field f = fields[i]; if (!f.getType().isPrimitive() && - Modifier.isStatic(f.getModifiers())) { + !Modifier.isStatic(f.getModifiers())) { try { f.setAccessible(true); - f.set(null, null); + f.set(test, null); } catch (Exception ignored) { // Nothing we can do about it. } } } - // don't cleanup the superclass for now - //cleanup(clazz.getSuperclass()); + clazz = clazz.getSuperclass(); } } diff --git a/test-runner/android/test/SingleLaunchActivityTestCase.java b/test-runner/android/test/SingleLaunchActivityTestCase.java index 8d43b732cf85747763521523c982da5c50a282f4..b63b3ce19759ccda07e65c80e653c44e7921aa03 100644 --- a/test-runner/android/test/SingleLaunchActivityTestCase.java +++ b/test-runner/android/test/SingleLaunchActivityTestCase.java @@ -37,7 +37,11 @@ public abstract class SingleLaunchActivityTestCase private static boolean sActivityLaunchedFlag = false; /** - * @param pkg The package of the instrumentation. + * NOTE: The parameter pkg must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. */ public SingleLaunchActivityTestCase(String pkg, Class activityClass) { diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java index c1d2507dce6ca411461058a861d586994f95a61c..772d75c556a04a2115a345d1822cbd2c45e9149a 100644 --- a/test-runner/android/test/SyncBaseInstrumentation.java +++ b/test-runner/android/test/SyncBaseInstrumentation.java @@ -18,12 +18,10 @@ package android.test; import android.content.ContentResolver; import android.content.Context; -import android.content.ContentValues; import android.os.Bundle; +import android.os.RemoteException; import android.os.SystemClock; -import android.provider.Sync; import android.net.Uri; -import java.util.Map; /** * If you would like to test sync a single provider with an @@ -75,11 +73,11 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase { } protected void cancelSyncsandDisableAutoSync() { - Sync.Settings.QueryMap mSyncSettings = - new Sync.Settings.QueryMap(mContentResolver, true, null); - mSyncSettings.setListenForNetworkTickles(false); + try { + ContentResolver.getContentService().setListenForNetworkTickles(false); + } catch (RemoteException e) { + } mContentResolver.cancelSync(null); - mSyncSettings.close(); } /** @@ -88,34 +86,11 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase { * @return */ private boolean isSyncActive(String account, String authority) { - Sync.Pending.QueryMap pendingQueryMap = null; - Sync.Active.QueryMap activeQueryMap = null; try { - pendingQueryMap = new Sync.Pending.QueryMap(mContentResolver, false, null); - activeQueryMap = new Sync.Active.QueryMap(mContentResolver, false, null); - - if (pendingQueryMap.isPending(account, authority)) { - return true; - } - if (isActiveInActiveQueryMap(activeQueryMap, account, authority)) { - return true; - } + return ContentResolver.getContentService().isSyncActive(account, + authority); + } catch (RemoteException e) { return false; - } finally { - activeQueryMap.close(); - pendingQueryMap.close(); - } - } - - private boolean isActiveInActiveQueryMap(Sync.Active.QueryMap activemap, String account, - String authority) { - Map rows = activemap.getRows(); - for (ContentValues values : rows.values()) { - if (values.getAsString("account").equals(account) - && values.getAsString("authority").equals(authority)) { - return true; - } } - return false; } } diff --git a/test-runner/android/test/TestLocationProvider.java b/test-runner/android/test/TestLocationProvider.java index 00c1ce8b7aa2cc5c9b1b0bfaa206560b5514faaf..dded745d2d1f3e2fdc4271e1652392304a776996 100644 --- a/test-runner/android/test/TestLocationProvider.java +++ b/test-runner/android/test/TestLocationProvider.java @@ -18,16 +18,20 @@ package android.test; import android.location.Criteria; +import android.location.ILocationManager; +import android.location.ILocationProvider; import android.location.Location; -import android.location.LocationProviderImpl; +import android.location.LocationProvider; import android.os.Bundle; +import android.os.RemoteException; import android.os.SystemClock; +import android.util.Log; /** * @hide - This is part of a framework that is under development and should not be used for * active development. */ -public class TestLocationProvider extends LocationProviderImpl { +public class TestLocationProvider extends ILocationProvider.Stub { public static final String PROVIDER_NAME = "test"; public static final double LAT = 0; @@ -35,92 +39,136 @@ public class TestLocationProvider extends LocationProviderImpl { public static final double ALTITUDE = 10000; public static final float SPEED = 10; public static final float BEARING = 1; - public static final int STATUS = AVAILABLE; + public static final int STATUS = LocationProvider.AVAILABLE; + private static final long LOCATION_INTERVAL = 1000; + private static final String TAG = "TestLocationProvider"; + + private final ILocationManager mLocationManager; private Location mLocation; private boolean mEnabled; - - public TestLocationProvider() { - super(PROVIDER_NAME); + private TestLocationProviderThread mThread; + + private class TestLocationProviderThread extends Thread { + + private boolean mDone = false; + + public TestLocationProviderThread() { + super("TestLocationProviderThread"); + } + + public void run() { + // thread exits after disable() is called + synchronized (this) { + while (!mDone) { + try { + wait(LOCATION_INTERVAL); + } catch (InterruptedException e) { + } + + if (!mDone) { + TestLocationProvider.this.updateLocation(); + } + } + } + } + + synchronized void setDone() { + mDone = true; + notify(); + } + } + + public TestLocationProvider(ILocationManager locationManager) { + mLocationManager = locationManager; mLocation = new Location(PROVIDER_NAME); - updateLocation(); } - //LocationProvider methods - - @Override public int getAccuracy() { return Criteria.ACCURACY_COARSE; } - @Override public int getPowerRequirement() { return Criteria.NO_REQUIREMENT; } - @Override public boolean hasMonetaryCost() { return false; } - @Override public boolean requiresCell() { return false; } - @Override public boolean requiresNetwork() { return false; } - @Override public boolean requiresSatellite() { return false; } - @Override public boolean supportsAltitude() { return true; } - @Override public boolean supportsBearing() { return true; } - @Override public boolean supportsSpeed() { return true; } - //LocationProviderImpl methods - @Override - public void disable() { + public synchronized void disable() { mEnabled = false; + if (mThread != null) { + mThread.setDone(); + try { + mThread.join(); + } catch (InterruptedException e) { + } + mThread = null; + } } - @Override - public void enable() { - mEnabled = true; + public synchronized void enable() { + mEnabled = true; + mThread = new TestLocationProviderThread(); + mThread.start(); } - @Override public boolean isEnabled() { return mEnabled; } - @Override - public boolean getLocation(Location l) { - updateLocation(); - l.set(mLocation); - return true; - } - - @Override public int getStatus(Bundle extras) { return STATUS; } + public long getStatusUpdateTime() { + return 0; + } + + public void enableLocationTracking(boolean enable) { + } + + public void setMinTime(long minTime) { + } + + public void updateNetworkState(int state) { + } + + public boolean sendExtraCommand(String command, Bundle extras) { + return false; + } + + public void addListener(int uid) { + } + + public void removeListener(int uid) { + } + private void updateLocation() { long time = SystemClock.uptimeMillis(); long multiplier = (time/5000)%500000; @@ -134,6 +182,11 @@ public class TestLocationProvider extends LocationProviderImpl { extras.putInt("extraTest", 24); mLocation.setExtras(extras); mLocation.setTime(time); + try { + mLocationManager.reportLocation(mLocation); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling updateLocation"); + } } } diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java index e733dd1910b8ab6de109e1d8c92ff92489d32f19..bd39a14857e05e1e9d7722385716a44aee863674 100644 --- a/test-runner/android/test/mock/MockContext.java +++ b/test-runner/android/test/mock/MockContext.java @@ -386,4 +386,12 @@ public class MockContext extends Context { throws PackageManager.NameNotFoundException { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public float getApplicationScale() { + throw new UnsupportedOperationException(); + } } diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java index ea190e237144810aaaf0318fbf0d8a9d65a55fdf..bf1629fd48fff4844b8dfb47d6e451b6bfceec1c 100644 --- a/test-runner/android/test/mock/MockPackageManager.java +++ b/test-runner/android/test/mock/MockPackageManager.java @@ -284,9 +284,20 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** + * @hide - to match hiding in superclass + */ @Override public void installPackage(Uri packageURI, IPackageInstallObserver observer, - int flags) { + int flags, String installerPackageName) { + throw new UnsupportedOperationException(); + } + + /** + * @hide - to match hiding in superclass + */ + @Override + public String getInstallerPackageName(String packageName) { throw new UnsupportedOperationException(); } @@ -390,11 +401,6 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } - @Override - public void installPackage(Uri packageURI) { - throw new UnsupportedOperationException(); - } - @Override public int getPreferredActivities(List outFilters, List outActivities, String packageName) { diff --git a/tests/AndroidTests/res/values-port/configVarying.xml b/tests/AndroidTests/res/values-32dpi/configVarying.xml similarity index 86% rename from tests/AndroidTests/res/values-port/configVarying.xml rename to tests/AndroidTests/res/values-32dpi/configVarying.xml index 0e1f2474c53aee80ebb7a1851d4ec5fe82babbec..f903f0fdf7a101e1cf7656f53fd59329c24b191e 100644 --- a/tests/AndroidTests/res/values-port/configVarying.xml +++ b/tests/AndroidTests/res/values-32dpi/configVarying.xml @@ -15,8 +15,8 @@ --> - simple portrait + simple 32dpi - bag portrait + bag 32dpi diff --git a/tests/AndroidTests/res/values-320x200/configVarying.xml b/tests/AndroidTests/res/values-640x400/configVarying.xml similarity index 86% rename from tests/AndroidTests/res/values-320x200/configVarying.xml rename to tests/AndroidTests/res/values-640x400/configVarying.xml index ca2a2864a5c302660b8794aad9f6146552c74e1d..30332c0967b0ee55144b2a9e0845efaae7155976 100644 --- a/tests/AndroidTests/res/values-320x200/configVarying.xml +++ b/tests/AndroidTests/res/values-640x400/configVarying.xml @@ -15,8 +15,8 @@ --> - simple 320x200 + simple 640x400 - bag 320x200 + bag 640x400 diff --git a/tests/AndroidTests/res/values-fr-rFR/configVarying.xml b/tests/AndroidTests/res/values-fr-rFR/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..5ecac7caff8adc75437536118e0e2ede7f2dbd02 --- /dev/null +++ b/tests/AndroidTests/res/values-fr-rFR/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple fr FR + + bag fr FR + + diff --git a/tests/AndroidTests/res/values-fr/configVarying.xml b/tests/AndroidTests/res/values-fr/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..8413b5a7008693ce6e7a1ec2bf3c3e78ae584fdd --- /dev/null +++ b/tests/AndroidTests/res/values-fr/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple fr + + bag fr + + diff --git a/tests/AndroidTests/res/values-trackball/configVarying.xml b/tests/AndroidTests/res/values-mcc110-xx/configVarying.xml similarity index 86% rename from tests/AndroidTests/res/values-trackball/configVarying.xml rename to tests/AndroidTests/res/values-mcc110-xx/configVarying.xml index 0dec30012ea44b762f937d478482505abbd77a74..82e24355d035bb424e4f050925913a4adbde2e39 100644 --- a/tests/AndroidTests/res/values-trackball/configVarying.xml +++ b/tests/AndroidTests/res/values-mcc110-xx/configVarying.xml @@ -15,8 +15,8 @@ --> - simple trackball + simple mcc110 xx - bag trackball + bag mcc110 xx diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-mcc112/configVarying.xml similarity index 86% rename from tests/AndroidTests/res/values-finger/configVarying.xml rename to tests/AndroidTests/res/values-mcc112/configVarying.xml index 674787e60e7fc8a6fd2ab8ccae609d93b9263e12..9c05d77b6d7b7425efc453d623c095c21461fe75 100644 --- a/tests/AndroidTests/res/values-finger/configVarying.xml +++ b/tests/AndroidTests/res/values-mcc112/configVarying.xml @@ -15,8 +15,8 @@ --> - simple finger + simple mcc112 - bag finger + bag mcc112 diff --git a/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml b/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..fbc78882d8aa5d3142238aff54bf3926ada27cdc --- /dev/null +++ b/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple mnc220 xx + + bag mnc220 xx + + diff --git a/tests/AndroidTests/res/values-keyshidden/configVarying.xml b/tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml similarity index 85% rename from tests/AndroidTests/res/values-keyshidden/configVarying.xml rename to tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml index fdffc4d76622b2221f1f7418128ef25c9afd8a97..03bea33ae2d07af0ca3bfaaf600990748e01935b 100644 --- a/tests/AndroidTests/res/values-keyshidden/configVarying.xml +++ b/tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml @@ -15,8 +15,8 @@ --> - simple keyshidden + simple mnc222 32dpi - bag keyshidden + bag mnc222 32dpi diff --git a/tests/AndroidTests/res/values-qwerty/configVarying.xml b/tests/AndroidTests/res/values-mnc223/configVarying.xml similarity index 86% rename from tests/AndroidTests/res/values-qwerty/configVarying.xml rename to tests/AndroidTests/res/values-mnc223/configVarying.xml index 939f682e8809d634de24d692010e426d79ff0548..8936cbcb09bfc54ab5c83bbcc021d799d8178397 100644 --- a/tests/AndroidTests/res/values-qwerty/configVarying.xml +++ b/tests/AndroidTests/res/values-mnc223/configVarying.xml @@ -15,8 +15,8 @@ --> - simple qwerty + simple mnc223 - bag qwerty + bag mnc223 diff --git a/tests/AndroidTests/src/com/android/unit_tests/BitwiseStreamsTest.java b/tests/AndroidTests/src/com/android/unit_tests/BitwiseStreamsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a93524776d216647cfafad2ec63518e5cfffd306 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/BitwiseStreamsTest.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.unit_tests; + +import com.android.internal.util.BitwiseInputStream; +import com.android.internal.util.BitwiseOutputStream; +import com.android.internal.util.HexDump; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.util.Log; + +public class BitwiseStreamsTest extends AndroidTestCase { + private final static String LOG_TAG = "BitwiseStreamsTest"; + + @SmallTest + public void testOne() throws Exception { + int offset = 3; + byte[] inBuf = HexDump.hexStringToByteArray("FFDD"); + BitwiseOutputStream outStream = new BitwiseOutputStream(30); + outStream.skip(offset); + for (int i = 0; i < inBuf.length; i++) outStream.write(8, inBuf[i]); + byte[] outBuf = outStream.toByteArray(); + BitwiseInputStream inStream = new BitwiseInputStream(outBuf); + byte[] inBufDup = new byte[inBuf.length]; + inStream.skip(offset); + for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8); + assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup)); + } + + @SmallTest + public void testTwo() throws Exception { + int offset = 3; + byte[] inBuf = HexDump.hexStringToByteArray("11d4f29c0e9ad3c36e72584e064d9b53"); + BitwiseOutputStream outStream = new BitwiseOutputStream(30); + outStream.skip(offset); + for (int i = 0; i < inBuf.length; i++) outStream.write(8, inBuf[i]); + BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray()); + inStream.skip(offset); + byte[] inBufDup = new byte[inBuf.length]; + for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8); + assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup)); + } + + @SmallTest + public void testThree() throws Exception { + int offset = 4; + byte[] inBuf = HexDump.hexStringToByteArray("00031040900112488ea794e0"); + BitwiseOutputStream outStream = new BitwiseOutputStream(30); + outStream.skip(offset); + for (int i = 0; i < inBuf.length; i++) outStream.write(8, inBuf[i]); + BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray()); + inStream.skip(offset); + byte[] inBufDup = new byte[inBuf.length]; + for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8); + assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup)); + } + + @SmallTest + public void testFour() throws Exception { + int offset = 7; + byte[] inBuf = HexDump.hexStringToByteArray("00031040900112488ea794e0"); + BitwiseOutputStream outStream = new BitwiseOutputStream(30); + outStream.skip(offset); + for (int i = 0; i < inBuf.length; i++) { + outStream.write(5, inBuf[i] >>> 3); + outStream.write(3, inBuf[i] & 0x07); + } + BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray()); + inStream.skip(offset); + byte[] inBufDup = new byte[inBuf.length]; + for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8); + assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup)); + } + + @SmallTest + public void testFive() throws Exception { + int num_runs = 10; + long start = android.os.SystemClock.elapsedRealtime(); + for (int run = 0; run < num_runs; run++) { + int offset = run % 8; + byte[] inBuf = HexDump.hexStringToByteArray("00031040900112488ea794e0"); + BitwiseOutputStream outStream = new BitwiseOutputStream(30); + outStream.skip(offset); + for (int i = 0; i < inBuf.length; i++) { + outStream.write(5, inBuf[i] >>> 3); + outStream.write(3, inBuf[i] & 0x07); + } + BitwiseInputStream inStream = new BitwiseInputStream(outStream.toByteArray()); + inStream.skip(offset); + byte[] inBufDup = new byte[inBuf.length]; + for (int i = 0; i < inBufDup.length; i++) inBufDup[i] = inStream.read(8); + assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup)); + } + long end = android.os.SystemClock.elapsedRealtime(); + Log.d(LOG_TAG, "repeated encode-decode took " + (end - start) + " ms"); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b3e88e13e3f6f52e599a2efa37b587408163d370 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java @@ -0,0 +1,489 @@ +/* + * 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.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.cdma.sms.BearerData; +import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; +import com.android.internal.util.BitwiseInputStream; +import com.android.internal.util.BitwiseOutputStream; +import com.android.internal.util.HexDump; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import java.util.Iterator; + +import android.util.Log; + +public class CdmaSmsTest extends AndroidTestCase { + private final static String LOG_TAG = "Cdma_Sms_Test"; + + @SmallTest + public void testUserData7bitGsm() throws Exception { + String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("Test standard SMS", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAscii() throws Exception { + String pdu = "0003100160010610262d5ab500"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("bjjj", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAsciiTwo() throws Exception { + String pdu = "00031001d00109104539b4d052ebb3d0"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("SMS Rulz", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserDataIa5() throws Exception { + String pdu = "00031002100109184539b4d052ebb3d0"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("SMS Rulz", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAsciiFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "Test standard SMS"; + userData.msgEncoding = UserData.ENCODING_7BIT_ASCII; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitGsmFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "Test standard SMS"; + userData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testUserDataUtf16Feedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "\u0160u\u1E5B\u0301r\u1ECFg\uD835\uDC1At\u00E9\u4E002\u3042"; + userData.msgEncoding = UserData.ENCODING_UNICODE_16; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.msgEncoding = UserData.ENCODING_OCTET; + userData.msgEncodingSet = false; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testReplyOption() throws Exception { + String pdu1 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87450080a0180"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Acknowledgement 1", bd1.userData.payloadStr); + assertEquals(true, bd1.userAckReq); + assertEquals(false, bd1.deliveryAckReq); + assertEquals(false, bd1.readAckReq); + assertEquals(false, bd1.reportReq); + String pdu2 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87490080a0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals("Test Acknowledgement 2", bd2.userData.payloadStr); + assertEquals(false, bd2.userAckReq); + assertEquals(true, bd2.deliveryAckReq); + assertEquals(false, bd2.readAckReq); + assertEquals(false, bd2.reportReq); + String pdu3 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d874d0080a0120"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals("Test Acknowledgement 3", bd3.userData.payloadStr); + assertEquals(false, bd3.userAckReq); + assertEquals(false, bd3.deliveryAckReq); + assertEquals(true, bd3.readAckReq); + assertEquals(false, bd3.reportReq); + String pdu4 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87510080a0110"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals("Test Acknowledgement 4", bd4.userData.payloadStr); + assertEquals(false, bd4.userAckReq); + assertEquals(false, bd4.deliveryAckReq); + assertEquals(false, bd4.readAckReq); + assertEquals(true, bd4.reportReq); + } + + @SmallTest + public void testReplyOptionFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test reply option"; + bearerData.userData = userData; + bearerData.userAckReq = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(true, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.userAckReq = false; + bearerData.deliveryAckReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(true, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.deliveryAckReq = false; + bearerData.readAckReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(true, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.readAckReq = false; + bearerData.reportReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(true, revBearerData.reportReq); + } + + @SmallTest + public void testNumberOfMessages() throws Exception { + String pdu1 = "000310409001124896a794e07595f69f199540ea759a0dc8e00b0163"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Voice mail 99", bd1.userData.payloadStr); + assertEquals(99, bd1.numberOfMessages); + String pdu2 = "00031040900113489ea794e07595f69f199540ea759a0988c0600b0164"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals("Test Voice mail 100", bd2.userData.payloadStr); + assertEquals(100, bd2.numberOfMessages); + } + + @SmallTest + public void testNumberOfMessagesFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test message count"; + bearerData.userData = userData; + bearerData.numberOfMessages = 27; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(bearerData.numberOfMessages, revBearerData.numberOfMessages); + } + + @SmallTest + public void testCallbackNum() throws Exception { + String pdu1 = "00031040900112488ea794e070d436cb638bc5e035ce2f97900e06910431323334"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Callback nbr", bd1.userData.payloadStr); + assertEquals(CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR, bd1.callbackNumber.digitMode); + assertEquals(CdmaSmsAddress.TON_INTERNATIONAL_OR_IP, bd1.callbackNumber.ton); + assertEquals(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK, bd1.callbackNumber.numberMode); + assertEquals(CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY, bd1.callbackNumber.numberPlan); + assertEquals("1234", bd1.callbackNumber.address); + } + + @SmallTest + public void testCallbackNumDtmf() throws Exception { + String pdu1 = "00031002300109104539b4d052ebb3d00e07052d4c90a55080"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("SMS Rulz", bd1.userData.payloadStr); + assertEquals(CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF, bd1.callbackNumber.digitMode); + assertEquals(CdmaSmsAddress.TON_UNKNOWN, bd1.callbackNumber.ton); + assertEquals(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK, bd1.callbackNumber.numberMode); + assertEquals(CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN, bd1.callbackNumber.numberPlan); + assertEquals("5099214001", bd1.callbackNumber.address); + } + + @SmallTest + public void testCallbackNumFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test callback number"; + bearerData.userData = userData; + CdmaSmsAddress addr = new CdmaSmsAddress(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; + addr.ton = CdmaSmsAddress.TON_NATIONAL_OR_EMAIL; + addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; + addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN; + addr.address = "8005551212"; + addr.numberOfDigits = (byte)addr.address.length(); + bearerData.callbackNumber = addr; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + CdmaSmsAddress revAddr = revBearerData.callbackNumber; + assertEquals(addr.digitMode, revAddr.digitMode); + assertEquals(addr.ton, revAddr.ton); + assertEquals(addr.numberMode, revAddr.numberMode); + assertEquals(addr.numberPlan, revAddr.numberPlan); + assertEquals(addr.numberOfDigits, revAddr.numberOfDigits); + assertEquals(addr.address, revAddr.address); + addr.address = "8*55#1012"; + addr.numberOfDigits = (byte)addr.address.length(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + revAddr = revBearerData.callbackNumber; + assertEquals(addr.digitMode, revAddr.digitMode); + assertEquals(addr.numberOfDigits, revAddr.numberOfDigits); + assertEquals(addr.address, revAddr.address); + } + + @SmallTest + public void testMsgCenterTimeStampFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test message center timestamp"; + bearerData.userData = userData; + bearerData.timeStamp = HexDump.hexStringToByteArray("112233445566"); + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(HexDump.toHexString(bearerData.timeStamp), + HexDump.toHexString(revBearerData.timeStamp)); + } + + @SmallTest + public void testPrivacyIndicator() throws Exception { + String pdu1 = "0003104090010c485f4194dfea34becf61b840090140"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.privacy, BearerData.PRIVACY_RESTRICTED); + String pdu2 = "0003104090010c485f4194dfea34becf61b840090180"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.privacy, BearerData.PRIVACY_CONFIDENTIAL); + String pdu3 = "0003104090010c485f4194dfea34becf61b8400901c0"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.privacy, BearerData.PRIVACY_SECRET); + } + + @SmallTest + public void testPrivacyIndicatorFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test privacy indicator"; + bearerData.userData = userData; + bearerData.privacy = BearerData.PRIVACY_SECRET; + bearerData.privacyIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.privacyIndicatorSet, true); + assertEquals(revBearerData.privacy, BearerData.PRIVACY_SECRET); + bearerData.privacy = BearerData.PRIVACY_RESTRICTED; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.privacy, BearerData.PRIVACY_RESTRICTED); + } + + @SmallTest + public void testMsgDeliveryAlert() throws Exception { + String pdu1 = "0003104090010d4866a794e07055965b91d040300c0100"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.alert, 0); + assertEquals(bd1.userData.payloadStr, "Test Alert 0"); + String pdu2 = "0003104090010d4866a794e07055965b91d140300c0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.alert, 1); + assertEquals(bd2.userData.payloadStr, "Test Alert 1"); + String pdu3 = "0003104090010d4866a794e07055965b91d240300c0180"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.alert, 2); + assertEquals(bd3.userData.payloadStr, "Test Alert 2"); + String pdu4 = "0003104090010d4866a794e07055965b91d340300c01c0"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.alert, 3); + assertEquals(bd4.userData.payloadStr, "Test Alert 3"); + } + + @SmallTest + public void testMiscParams() throws Exception { + String pdu1 = "00031002400109104539b4d052ebb3d00c0180"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.alert, BearerData.ALERT_MEDIUM_PRIO); + assertEquals(bd1.userData.payloadStr, "SMS Rulz"); + String pdu2 = "00031002500109104539b4d052ebb3d00801800901c0"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.priority, BearerData.PRIORITY_URGENT); + assertEquals(bd2.privacy, BearerData.PRIVACY_SECRET); + assertEquals(bd2.userData.payloadStr, "SMS Rulz"); + String pdu3 = "00031002600109104539b4d052ebb3d00901400c01c0"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.privacy, BearerData.PRIVACY_RESTRICTED); + assertEquals(bd3.alert, BearerData.ALERT_HIGH_PRIO); + assertEquals(bd3.userData.payloadStr, "SMS Rulz"); + String pdu4 = "00031002700109104539b4d052ebb3d00f0105"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.displayMode, BearerData.DISPLAY_MODE_IMMEDIATE); + assertEquals(bd4.userData.payloadStr, "SMS Rulz"); + } + @SmallTest + public void testMsgDeliveryAlertFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test message delivery alert"; + bearerData.userData = userData; + bearerData.alert = BearerData.ALERT_MEDIUM_PRIO; + bearerData.alertIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.alertIndicatorSet, true); + assertEquals(revBearerData.alert, bearerData.alert); + bearerData.alert = BearerData.ALERT_HIGH_PRIO; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.alertIndicatorSet, true); + assertEquals(revBearerData.alert, bearerData.alert); + } + + @SmallTest + public void testLanguageIndicator() throws Exception { + String pdu1 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0101"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.userData.payloadStr, "Test Language indicator"); + assertEquals(bd1.language, BearerData.LANGUAGE_ENGLISH); + String pdu2 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0106"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.userData.payloadStr, "Test Language indicator"); + assertEquals(bd2.language, BearerData.LANGUAGE_CHINESE); + } + + @SmallTest + public void testLanguageIndicatorFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test language indicator"; + bearerData.userData = userData; + bearerData.language = BearerData.LANGUAGE_ENGLISH; + bearerData.languageIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.languageIndicatorSet, true); + assertEquals(revBearerData.language, bearerData.language); + bearerData.language = BearerData.LANGUAGE_KOREAN; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.languageIndicatorSet, true); + assertEquals(revBearerData.language, bearerData.language); + } + + @SmallTest + public void testDisplayMode() throws Exception { + String pdu1 = "0003104090010c485f4194dfea34becf61b8400f0100"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + //Log.d(LOG_TAG, "bd1 = " + bd1); + assertEquals(bd1.displayMode, BearerData.DISPLAY_MODE_IMMEDIATE); + String pdu2 = "0003104090010c485f4194dfea34becf61b8400f0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.displayMode, BearerData.DISPLAY_MODE_DEFAULT); + String pdu3 = "0003104090010c485f4194dfea34becf61b8400f0180"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.displayMode, BearerData.DISPLAY_MODE_USER); + } + + @SmallTest + public void testDisplayModeFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test display mode"; + bearerData.userData = userData; + bearerData.displayMode = BearerData.DISPLAY_MODE_IMMEDIATE; + bearerData.displayModeSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.displayModeSet, true); + assertEquals(revBearerData.displayMode, bearerData.displayMode); + bearerData.displayMode = BearerData.DISPLAY_MODE_USER; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.displayModeSet, true); + assertEquals(revBearerData.displayMode, bearerData.displayMode); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java index ce0b53d864e3a361885bb6b5ed67c86ff2a6fc5c..360352b288823ac42a973982e79fe46a1ac78115 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java @@ -16,10 +16,10 @@ package com.android.unit_tests; -import com.android.internal.telephony.gsm.GsmAlphabet; -import com.android.internal.telephony.gsm.SmsHeader; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.gsm.SmsMessage; import com.android.internal.util.HexDump; -import android.telephony.gsm.SmsMessage; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java index 09e3b0290a8bddf55bcb5512deebcfba4051a289..f3c15422073b2adb0b0d1620d59c705eda1c06ef 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java @@ -23,27 +23,11 @@ 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.ActivityInstrumentationTestCase2; 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: @@ -52,7 +36,7 @@ import java.util.List; * -e class com.android.unit_tests.SearchManagerTest \ * com.android.unit_tests/android.test.InstrumentationTestRunner */ -public class SearchManagerTest extends ActivityInstrumentationTestCase { +public class SearchManagerTest extends ActivityInstrumentationTestCase2 { // 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 @@ -71,18 +55,6 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase 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/SearchablesTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bdf67ba86ac70bebce8d967e505046d300b303f8 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.unit_tests; + +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.RemoteException; +import android.server.search.SearchableInfo; +import android.server.search.Searchables; +import android.server.search.SearchableInfo.ActionKeyInfo; +import android.test.AndroidTestCase; +import android.test.MoreAsserts; +import android.test.mock.MockContext; +import android.test.mock.MockPackageManager; +import android.test.suitebuilder.annotation.SmallTest; +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.SearchablesTest \ + * com.android.unit_tests/android.test.InstrumentationTestRunner + */ +@SmallTest +public class SearchablesTest extends AndroidTestCase { + + /* + * 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 + */ + + /** + * 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). + */ + public void testSearchableGoogleSearch() { + // test basic array & hashmap + Searchables searchables = new Searchables(mContext); + searchables.buildSearchableList(); + + // 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 = searchables.getSearchableInfo(thisActivity); + assertNotNull(si); + assertEquals(thisActivity, si.getSearchActivity()); + + 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) + */ + public void testNonSearchable() { + // test basic array & hashmap + Searchables searchables = new Searchables(mContext); + searchables.buildSearchableList(); + + // 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 = searchables.getSearchableInfo(nonActivity); + assertNull(si); + } + + /** + * Test that there is a default searchable (aka global search provider). + */ + public void testDefaultSearchable() { + Searchables searchables = new Searchables(mContext); + searchables.buildSearchableList(); + SearchableInfo si = searchables.getDefaultSearchable(); + checkSearchable(si); + assertTrue(searchables.isDefaultSearchable(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 + + */ + public void testSearchablesListReal() { + MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager()); + MyMockContext mockContext = new MyMockContext(mContext, mockPM); + + // build item list with real-world source data + mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH); + Searchables searchables = new Searchables(mockContext); + searchables.buildSearchableList(); + // tests with "real" searchables (deprecate, this should be a unit test) + ArrayList searchablesList = searchables.getSearchablesList(); + int count = searchablesList.size(); + assertTrue(count >= 1); // this isn't really a unit test + checkSearchables(searchablesList); + ArrayList global = searchables.getSearchablesInGlobalSearchList(); + checkSearchables(global); + } + + /** + * This round of tests confirms good operations with "zero" searchables found + */ + public void testSearchablesListEmpty() { + MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager()); + MyMockContext mockContext = new MyMockContext(mContext, mockPM); + + mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO); + Searchables searchables = new Searchables(mockContext); + searchables.buildSearchableList(); + ArrayList searchablesList = searchables.getSearchablesList(); + assertNotNull(searchablesList); + MoreAsserts.assertEmpty(searchablesList); + ArrayList global = searchables.getSearchablesInGlobalSearchList(); + MoreAsserts.assertEmpty(global); + } + + /** + * 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); + checkSearchable(si); + } + } + + private void checkSearchable(SearchableInfo si) { + assertNotNull(si); + assertTrue(si.getLabelId() != 0); // This must be a useable string + assertNotEmpty(si.getSearchActivity().getClassName()); + assertNotEmpty(si.getSearchActivity().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.getKeyCode(), KeyEvent.KEYCODE_CALL); + // one of these three fields must be non-null & non-empty + boolean m1 = (ai.getQueryActionMsg() != null) && (ai.getQueryActionMsg().length() > 0); + boolean m2 = (ai.getSuggestActionMsg() != null) && (ai.getSuggestActionMsg().length() > 0); + boolean m3 = (ai.getSuggestActionMsgColumn() != null) && + (ai.getSuggestActionMsgColumn().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(); + } + } + + @Override + public ResolveInfo resolveActivity(Intent intent, int flags) { + assertNotNull(intent); + assertEquals(intent.getAction(), SearchManager.INTENT_ACTION_GLOBAL_SEARCH); + switch (mSearchablesMode) { + case SEARCHABLES_PASSTHROUGH: + return mRealPackageManager.resolveActivity(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/content/ConfigTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java index 1ea83c3b952dcc4b3335315abc4f531c7137c527..e6639d3720cd6647f21143a291f1164bccd9ff63 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java @@ -98,7 +98,7 @@ public class ConfigTest extends AndroidTestCase { mMetrics = new DisplayMetrics(); mMetrics.widthPixels = 200; mMetrics.heightPixels = 320; - mMetrics.density = 120; + mMetrics.density = 1; } void setProperty(properties p, int value) { @@ -131,7 +131,9 @@ public class ConfigTest extends AndroidTestCase { mMetrics.heightPixels = value; break; case DENSITY: - mMetrics.density = value; + // this is the ratio from the standard + + mMetrics.density = (((float)value)/((float)DisplayMetrics.DEFAULT_DENSITY)); break; default: assert(false); @@ -187,18 +189,16 @@ public class ConfigTest extends AndroidTestCase { */ TotalConfig config = new TotalConfig(); Resources res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple default"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag default"}); + checkValue(res, R.configVarying.simple, "simple default"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag default"}); config = new TotalConfig(); config.setProperty(properties.LANGUAGE, "xx"); res = config.getResources(); -// got simple xx 32dpi -// checkValue(res, R.configVarying.simple, "simple xx"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag xx"}); + checkValue(res, R.configVarying.simple, "simple xx"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag xx"}); config = new TotalConfig(); config.setProperty(properties.LANGUAGE, "xx"); @@ -225,155 +225,160 @@ public class ConfigTest extends AndroidTestCase { config = new TotalConfig(); config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_NOTOUCH); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple notouch"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag notouch"}); + checkValue(res, R.configVarying.simple, "simple notouch"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag notouch"}); config = new TotalConfig(); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_FINGER); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple finger"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag finger"}); + checkValue(res, R.configVarying.simple, "simple stylus"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag stylus"}); config = new TotalConfig(); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS); res = config.getResources(); -// got simple 32dpi stylus -// checkValue(res, R.configVarying.simple, "simple stylus"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag stylus"}); + checkValue(res, R.configVarying.simple, "simple nokeys"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag nokeys"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple nokeys"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag nokeys"}); + checkValue(res, R.configVarying.simple, "simple 12key"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 12key"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_QWERTY); + config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple qwerty"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag qwerty"}); + checkValue(res, R.configVarying.simple, "simple keysexposed"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag keysexposed"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_NONAV); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple 12key"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag 12key"}); + checkValue(res, R.configVarying.simple, "simple nonav"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag nonav"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_YES); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple keyshidden"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag keyshidden"}); + checkValue(res, R.configVarying.simple, "simple dpad"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag dpad"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_WHEEL); res = config.getResources(); -// got simple 32dpi keysexposed -// checkValue(res, R.configVarying.simple, "simple keysexposed"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag keysexposed"}); + checkValue(res, R.configVarying.simple, "simple wheel"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag wheel"}); config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_NONAV); + config.setProperty(properties.HEIGHT, 480); + config.setProperty(properties.WIDTH, 320); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple nonav"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag nonav"}); + checkValue(res, R.configVarying.simple, "simple 480x320"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 480x320"}); config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); + config.setProperty(properties.DENSITY, 240); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple dpad"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag dpad"}); + checkValue(res, R.configVarying.simple, "simple 240dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 240dpi"}); config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_TRACKBALL); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple trackball"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag trackball"}); + checkValue(res, R.configVarying.simple, "simple landscape"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag landscape"}); config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_WHEEL); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple wheel"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag wheel"}); + checkValue(res, R.configVarying.simple, "simple square"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag square"}); + } + + @MediumTest + public void testDensity() throws Exception { + // have 32, 240 and the default 160 content. + // rule is that closest wins, with down scaling (larger content) + // being twice as nice as upscaling. + // transition at H/2 * (-1 +/- sqrt(1+8L/H)) + // SO, X < 49 goes to 32 + // 49 >= X < 182 goes to 160 + // X >= 182 goes to 240 + TotalConfig config = new TotalConfig(); + config.setProperty(properties.DENSITY, 2); + Resources res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple 32dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 32dpi"}); config = new TotalConfig(); - config.setProperty(properties.HEIGHT, 320); - config.setProperty(properties.WIDTH, 200); + config.setProperty(properties.DENSITY, 32); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple 320x200"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag 320x200"}); + checkValue(res, R.configVarying.simple, "simple 32dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 32dpi"}); config = new TotalConfig(); - config.setProperty(properties.HEIGHT, 480); - config.setProperty(properties.WIDTH, 320); + config.setProperty(properties.DENSITY, 48); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple 480x320"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag 480x320"}); + checkValue(res, R.configVarying.simple, "simple 32dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 32dpi"}); config = new TotalConfig(); - config.setProperty(properties.DENSITY, 240); + config.setProperty(properties.DENSITY, 49); res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 240dpi"); + checkValue(res, R.configVarying.simple, "simple default"); checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 240dpi"}); + R.styleable.TestConfig, new String[]{"bag default"}); config = new TotalConfig(); - config.setProperty(properties.DENSITY, 120); + config.setProperty(properties.DENSITY, 150); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple 120dpi"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag 120dpi"}); + checkValue(res, R.configVarying.simple, "simple default"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag default"}); config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE); + config.setProperty(properties.DENSITY, 181); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple landscape"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag landscape"}); + checkValue(res, R.configVarying.simple, "simple default"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag default"}); config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_PORTRAIT); + config.setProperty(properties.DENSITY, 182); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple portrait"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag portrait"}); + checkValue(res, R.configVarying.simple, "simple 240dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 240dpi"}); config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + config.setProperty(properties.DENSITY, 239); res = config.getResources(); -// got simple square 32dpi -// checkValue(res, R.configVarying.simple, "simple square"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag square"}); + checkValue(res, R.configVarying.simple, "simple 240dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 240dpi"}); + + config = new TotalConfig(); + config.setProperty(properties.DENSITY, 490); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple 240dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 240dpi"}); } // TODO - add tests for special cases - ie, other key params seem ignored if @@ -407,10 +412,9 @@ public class ConfigTest extends AndroidTestCase { config = new TotalConfig(); config.setProperty(properties.MNC, 333); res = config.getResources(); -// got simple 24dpi -// checkValue(res, R.configVarying.simple, "simple default"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag default"}); + checkValue(res, R.configVarying.simple, "simple default"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag default"}); } @MediumTest @@ -419,13 +423,31 @@ public class ConfigTest extends AndroidTestCase { * Verify that in cases of ties, the specific ordering is followed */ - /* full A + B + C doesn't exist. Do we get A + C or B + C? + /** + * Precidence order: mcc, mnc, locale, orientation, density, + * touchscreen, hidden, keyboard, navigation, width-height + */ + + /** + * verify mcc trumps mnc. Have 110-xx, 220-xx but no 110-220 + * so with is selected? Should be mcc110-xx. */ TotalConfig config = new TotalConfig(); + config.setProperty(properties.MCC, 110); + config.setProperty(properties.MNC, 220); + config.setProperty(properties.LANGUAGE, "xx"); + Resources res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple mcc110 xx"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag mcc110 xx"}); + + /* full A + B + C doesn't exist. Do we get A + C or B + C? + */ + config = new TotalConfig(); config.setProperty(properties.MCC, 111); config.setProperty(properties.MNC, 222); config.setProperty(properties.LANGUAGE, "xx"); - Resources res = config.getResources(); + res = config.getResources(); checkValue(res, R.configVarying.simple, "simple mcc111 mnc222"); checkValue(res, R.configVarying.bag, R.styleable.TestConfig, new String[]{"bag mcc111 mnc222"}); @@ -433,7 +455,8 @@ public class ConfigTest extends AndroidTestCase { config = new TotalConfig(); config.setProperty(properties.MNC, 222); config.setProperty(properties.LANGUAGE, "xx"); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + config.setProperty(properties.ORIENTATION, + Configuration.ORIENTATION_SQUARE); res = config.getResources(); checkValue(res, R.configVarying.simple, "simple mnc222 xx"); checkValue(res, R.configVarying.bag, @@ -441,60 +464,77 @@ public class ConfigTest extends AndroidTestCase { config = new TotalConfig(); config.setProperty(properties.LANGUAGE, "xx"); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + config.setProperty(properties.ORIENTATION, + Configuration.ORIENTATION_SQUARE); config.setProperty(properties.DENSITY, 32); res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple xx 32dpi"); + checkValue(res, R.configVarying.simple, "simple xx square"); checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag xx 32dpi"}); + R.styleable.TestConfig, new String[]{"bag xx square"}); config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + config.setProperty(properties.ORIENTATION, + Configuration.ORIENTATION_SQUARE); config.setProperty(properties.DENSITY, 32); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); + config.setProperty(properties.TOUCHSCREEN, + Configuration.TOUCHSCREEN_STYLUS); res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 32dpi stylus"); + checkValue(res, R.configVarying.simple, "simple square 32dpi"); checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 32dpi stylus"}); + R.styleable.TestConfig, new String[]{"bag square 32dpi"}); config = new TotalConfig(); config.setProperty(properties.DENSITY, 32); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); - config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + config.setProperty(properties.TOUCHSCREEN, + Configuration.TOUCHSCREEN_STYLUS); + config.setProperty(properties.KEYBOARDHIDDEN, + Configuration.KEYBOARDHIDDEN_NO); res = config.getResources(); checkValue(res, R.configVarying.simple, "simple 32dpi stylus"); checkValue(res, R.configVarying.bag, R.styleable.TestConfig, new String[]{"bag 32dpi stylus"}); config = new TotalConfig(); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); - config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + config.setProperty(properties.TOUCHSCREEN, + Configuration.TOUCHSCREEN_STYLUS); + config.setProperty(properties.KEYBOARDHIDDEN, + Configuration.KEYBOARDHIDDEN_NO); config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); res = config.getResources(); -// got simple 32dpi stylus -// checkValue(res, R.configVarying.simple, "simple stylus 12key"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag stylus 12key"}); + checkValue(res, R.configVarying.simple, "simple stylus keysexposed"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag stylus keysexposed"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + config.setProperty(properties.KEYBOARDHIDDEN, + Configuration.KEYBOARDHIDDEN_NO); config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); + config.setProperty(properties.NAVIGATION, + Configuration.NAVIGATION_DPAD); res = config.getResources(); -// got simple 32dpi exposed -// checkValue(res, R.configVarying.simple, "simple stylus keysexposed"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag stylus keysexposed"}); + checkValue(res, R.configVarying.simple, "simple keysexposed 12key"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag keysexposed 12key"}); config = new TotalConfig(); config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); + config.setProperty(properties.NAVIGATION, + Configuration.NAVIGATION_DPAD); config.setProperty(properties.HEIGHT, 63); config.setProperty(properties.WIDTH, 57); res = config.getResources(); -// got simple 240dpi -// checkValue(res, R.configVarying.simple, "simple 12key dpad"); -// checkValue(res, R.configVarying.bag, -// R.styleable.TestConfig, new String[]{"bag 12key dpad"}); + checkValue(res, R.configVarying.simple, "simple 12key dpad"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 12key dpad"}); + + config = new TotalConfig(); + config.setProperty(properties.NAVIGATION, + Configuration.NAVIGATION_DPAD); + config.setProperty(properties.HEIGHT, 640); + config.setProperty(properties.WIDTH, 400); + res = config.getResources(); + checkValue(res, R.configVarying.simple, "simple dpad"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag dpad"}); } } diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java index 36805b15e864c852c3702ff11bc7deddc921a9b6..dee6e38c622364b280e0a04ac184055ad6b93909 100644 --- a/tests/CoreTests/android/content/SyncStorageEngineTest.java +++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java @@ -20,7 +20,6 @@ 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 { @@ -39,7 +38,7 @@ public class SyncStorageEngineTest extends AndroidTestCase { long time0 = 1000; long historyId = engine.insertStartSyncEvent( - account, authority, time0, Sync.History.SOURCE_LOCAL); + account, authority, time0, SyncStorageEngine.SOURCE_LOCAL); long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2; engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0); } diff --git a/tests/CoreTests/android/core/SocketTest.java b/tests/CoreTests/android/core/SocketTest.java index b64c1568ec9eed80bf9ac16d316d36d419940d4b..9db6077476a0280621acaeed01e47699bc54b9a4 100644 --- a/tests/CoreTests/android/core/SocketTest.java +++ b/tests/CoreTests/android/core/SocketTest.java @@ -178,29 +178,35 @@ public class SocketTest extends TestCase { 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 issue 1018016, connecting ignored a set timeout. +// +// Disabled because test behaves differently depending on networking +// environment. It works fine in the emulator and one the device with +// WLAN, but when 3G comes into play, the possible existence of a +// proxy makes it fail. +// +// @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) diff --git a/tests/CoreTests/android/location/LocationManagerProximityTest.java b/tests/CoreTests/android/location/LocationManagerProximityTest.java index e1501e34e528dc1cc3b12d7af27d23be8eb712c4..3f43bcf081484bfc2823277143061689478e9612 100644 --- a/tests/CoreTests/android/location/LocationManagerProximityTest.java +++ b/tests/CoreTests/android/location/LocationManagerProximityTest.java @@ -52,11 +52,7 @@ public class LocationManagerProximityTest extends AndroidTestCase { 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; + private static final String PROVIDER_NAME = "test"; @Override protected void setUp() throws Exception { @@ -84,6 +80,7 @@ public class LocationManagerProximityTest extends AndroidTestCase { false, // upportsBearing, Criteria.POWER_MEDIUM, // powerRequirement Criteria.ACCURACY_FINE); // accuracy + mLocationManager.setTestProviderEnabled(PROVIDER_NAME, true); } @Override diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java b/tests/CoreTests/com/android/internal/telephony/AdnRecordTest.java similarity index 83% rename from tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java rename to tests/CoreTests/com/android/internal/telephony/AdnRecordTest.java index 6cafdf0a8cd7edf5618c4cbe8bc067305e44a257..8a4a285212b1c1c82e274c1c429753bcd8e740cf 100644 --- a/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java +++ b/tests/CoreTests/com/android/internal/telephony/AdnRecordTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import junit.framework.TestCase; import android.test.suitebuilder.annotation.SmallTest; @@ -32,7 +32,7 @@ public class AdnRecordTest extends TestCase { // Typical record // adn = new AdnRecord( - SimUtils.hexStringToBytes("566F696365204D61696C07918150367742F3FFFFFFFFFFFF")); + IccUtils.hexStringToBytes("566F696365204D61696C07918150367742F3FFFFFFFFFFFF")); assertEquals("Voice Mail", adn.getAlphaTag()); assertEquals("+18056377243", adn.getNumber()); @@ -42,7 +42,7 @@ public class AdnRecordTest extends TestCase { // Empty records, empty strings // adn = new AdnRecord( - SimUtils.hexStringToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + IccUtils.hexStringToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); assertEquals("", adn.getAlphaTag()); assertEquals("", adn.getNumber()); @@ -51,7 +51,7 @@ public class AdnRecordTest extends TestCase { // // Record too short // - adn = new AdnRecord(SimUtils.hexStringToBytes( "FF")); + adn = new AdnRecord(IccUtils.hexStringToBytes( "FF")); assertEquals("", adn.getAlphaTag()); assertEquals("", adn.getNumber()); @@ -61,7 +61,7 @@ public class AdnRecordTest extends TestCase { // TOA = 0xff ("control string") // adn = new AdnRecord( - SimUtils.hexStringToBytes("566F696365204D61696C07FF8150367742F3FFFFFFFFFFFF")); + IccUtils.hexStringToBytes("566F696365204D61696C07FF8150367742F3FFFFFFFFFFFF")); assertEquals("Voice Mail", adn.getAlphaTag()); assertEquals("18056377243", adn.getNumber()); @@ -71,7 +71,7 @@ public class AdnRecordTest extends TestCase { // TOA = 0x81 (unknown) // adn = new AdnRecord( - SimUtils.hexStringToBytes("566F696365204D61696C07818150367742F3FFFFFFFFFFFF")); + IccUtils.hexStringToBytes("566F696365204D61696C07818150367742F3FFFFFFFFFFFF")); assertEquals("Voice Mail", adn.getAlphaTag()); assertEquals("18056377243", adn.getNumber()); @@ -81,7 +81,7 @@ public class AdnRecordTest extends TestCase { // Number Length is too long // adn = new AdnRecord( - SimUtils.hexStringToBytes("566F696365204D61696C0F918150367742F3FFFFFFFFFFFF")); + IccUtils.hexStringToBytes("566F696365204D61696C0F918150367742F3FFFFFFFFFFFF")); assertEquals("Voice Mail", adn.getAlphaTag()); assertEquals("", adn.getNumber()); @@ -91,7 +91,7 @@ public class AdnRecordTest extends TestCase { // Number Length is zero (invalid) // adn = new AdnRecord( - SimUtils.hexStringToBytes("566F696365204D61696C00918150367742F3FFFFFFFFFFFF")); + IccUtils.hexStringToBytes("566F696365204D61696C00918150367742F3FFFFFFFFFFFF")); assertEquals("Voice Mail", adn.getAlphaTag()); assertEquals("", adn.getNumber()); @@ -101,7 +101,7 @@ public class AdnRecordTest extends TestCase { // Number Length is 2, first number byte is FF, TOA is international // adn = new AdnRecord( - SimUtils.hexStringToBytes("566F696365204D61696C0291FF50367742F3FFFFFFFFFFFF")); + IccUtils.hexStringToBytes("566F696365204D61696C0291FF50367742F3FFFFFFFFFFFF")); assertEquals("Voice Mail", adn.getAlphaTag()); assertEquals("", adn.getNumber()); @@ -111,7 +111,7 @@ public class AdnRecordTest extends TestCase { // Number Length is 2, first number digit is valid, TOA is international // adn = new AdnRecord( - SimUtils.hexStringToBytes("566F696365204D61696C0291F150367742F3FFFFFFFFFFFF")); + IccUtils.hexStringToBytes("566F696365204D61696C0291F150367742F3FFFFFFFFFFFF")); assertEquals("Voice Mail", adn.getAlphaTag()); assertEquals("+1", adn.getNumber()); @@ -121,7 +121,7 @@ public class AdnRecordTest extends TestCase { // An extended record // adn = new AdnRecord( - SimUtils.hexStringToBytes( + IccUtils.hexStringToBytes( "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); assertEquals("Adgjm", adn.getAlphaTag()); @@ -129,7 +129,7 @@ public class AdnRecordTest extends TestCase { assertFalse(adn.isEmpty()); assertTrue(adn.hasExtendedRecord()); - adn.appendExtRecord(SimUtils.hexStringToBytes("0206092143658709ffffffffff")); + adn.appendExtRecord(IccUtils.hexStringToBytes("0206092143658709ffffffffff")); assertEquals("Adgjm", adn.getAlphaTag()); assertEquals("+18885551212,12345678901234567890", adn.getNumber()); @@ -139,7 +139,7 @@ public class AdnRecordTest extends TestCase { // An extended record with an invalid extension // adn = new AdnRecord( - SimUtils.hexStringToBytes( + IccUtils.hexStringToBytes( "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); assertEquals("Adgjm", adn.getAlphaTag()); @@ -147,7 +147,7 @@ public class AdnRecordTest extends TestCase { assertFalse(adn.isEmpty()); assertTrue(adn.hasExtendedRecord()); - adn.appendExtRecord(SimUtils.hexStringToBytes("0106092143658709ffffffffff")); + adn.appendExtRecord(IccUtils.hexStringToBytes("0106092143658709ffffffffff")); assertEquals("Adgjm", adn.getAlphaTag()); assertEquals("+18885551212,12345678", adn.getNumber()); @@ -157,7 +157,7 @@ public class AdnRecordTest extends TestCase { // An extended record with an invalid extension // adn = new AdnRecord( - SimUtils.hexStringToBytes( + IccUtils.hexStringToBytes( "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); assertEquals("Adgjm", adn.getAlphaTag()); @@ -165,7 +165,7 @@ public class AdnRecordTest extends TestCase { assertFalse(adn.isEmpty()); assertTrue(adn.hasExtendedRecord()); - adn.appendExtRecord(SimUtils.hexStringToBytes("020B092143658709ffffffffff")); + adn.appendExtRecord(IccUtils.hexStringToBytes("020B092143658709ffffffffff")); assertEquals("Adgjm", adn.getAlphaTag()); assertEquals("+18885551212,12345678", adn.getNumber()); diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java b/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java similarity index 98% rename from tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java rename to tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java index f36d96bba8111de94fab5a4a1cc2bdfdb2c3c4ca..5df89914ccca594907e08104fc386034eb13cc28 100644 --- a/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java +++ b/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import junit.framework.TestCase; @@ -216,12 +216,12 @@ public class GsmAlphabetTest extends TestCase { byte unpacked[]; - unpacked = SimUtils.hexStringToBytes("566F696365204D61696C"); + unpacked = IccUtils.hexStringToBytes("566F696365204D61696C"); assertEquals("Voice Mail", GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); - assertEquals(SimUtils.bytesToHexString(unpacked), - SimUtils.bytesToHexString( + assertEquals(IccUtils.bytesToHexString(unpacked), + IccUtils.bytesToHexString( GsmAlphabet.stringToGsm8BitPacked("Voice Mail"))); unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars); diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java b/tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java similarity index 92% rename from tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java rename to tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java index 6db230ffdc95cddd80d1f9076e9bd8f8d6bb0724..5d5d1f99ec055d8ae92c417f26da606d21fd8420 100644 --- a/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java +++ b/tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.test.suitebuilder.annotation.MediumTest; import com.android.internal.telephony.TestPhoneNotifier; +import com.android.internal.telephony.gsm.SmsMessage; 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; @@ -37,24 +37,24 @@ public class SMSDispatcherTest extends AndroidTestCase { Iterator elements; String[] lines = new String[2]; - - lines[0] = "+CMT: ,158"; + + 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; @@ -62,7 +62,7 @@ public class SMSDispatcherTest extends AndroidTestCase { Iterator elements; String[] lines = new String[2]; - + lines[0] = "+CMT: ,77"; lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F" @@ -74,7 +74,7 @@ public class SMSDispatcherTest extends AndroidTestCase { System.out.println("header = " + header); assertNotNull(header); assertNotNull(sms.getUserData()); - + elements = header.getElements().iterator(); assertNotNull(elements); } @@ -89,7 +89,7 @@ public class SMSDispatcherTest extends AndroidTestCase { + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874" + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb" + "eff8bc7ecfeffbffffffffffffffffffffffffffff"; - byte[] data = SimUtils.hexStringToBytes(s); + byte[] data = IccUtils.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/SimPhoneBookTest.java similarity index 78% rename from tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java rename to tests/CoreTests/com/android/internal/telephony/SimPhoneBookTest.java index db55bcae4f0eb15a954a57050037a44cfbd6589a..609e768790331c8b9785c5753570745eb0b8007a 100644 --- a/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java +++ b/tests/CoreTests/com/android/internal/telephony/SimPhoneBookTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.os.ServiceManager; import android.test.suitebuilder.annotation.Suppress; @@ -27,19 +27,19 @@ import junit.framework.TestCase; public class SimPhoneBookTest extends TestCase { public void testBasic() throws Exception { - ISimPhoneBook simPhoneBook = - ISimPhoneBook.Stub.asInterface(ServiceManager.getService("simphonebook")); + IIccPhoneBook simPhoneBook = + IIccPhoneBook.Stub.asInterface(ServiceManager.getService("simphonebook")); assertNotNull(simPhoneBook); - int size[] = simPhoneBook.getAdnRecordsSize(SimConstants.EF_ADN); + int size[] = simPhoneBook.getAdnRecordsSize(IccConstants.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); + List adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); // do it twice cause the second time shall read from cache only - adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); assertNotNull(adnRecordList); // Test for phone book update @@ -47,58 +47,58 @@ public class SimPhoneBookTest extends TestCase { 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 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) { + + 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, + boolean success = simPhoneBook.updateAdnRecordsInEfByIndex(IccConstants.EF_ADN, firstAdn.getAlphaTag(), firstAdn.getNumber(), adnIndex, pin2); - adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); AdnRecord tmpAdn = adnRecordList.get(listIndex); assertTrue(success); assertTrue(firstAdn.isEqual(tmpAdn)); // replace by search - success = simPhoneBook.updateAdnRecordsInEfBySearch(SimConstants.EF_ADN, + success = simPhoneBook.updateAdnRecordsInEfBySearch(IccConstants.EF_ADN, firstAdn.getAlphaTag(), firstAdn.getNumber(), secondAdn.getAlphaTag(), secondAdn.getNumber(), pin2); - adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.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, + success = simPhoneBook.updateAdnRecordsInEfBySearch(IccConstants.EF_ADN, secondAdn.getAlphaTag(), secondAdn.getNumber(), emptyAdn.getAlphaTag(), emptyAdn.getNumber(), pin2); - adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); tmpAdn = adnRecordList.get(listIndex); assertTrue(success); assertTrue(tmpAdn.isEmpty()); // restore the orginial adn - success = simPhoneBook.updateAdnRecordsInEfByIndex(SimConstants.EF_ADN, + success = simPhoneBook.updateAdnRecordsInEfByIndex(IccConstants.EF_ADN, originalAdn.getAlphaTag(), originalAdn.getNumber(), adnIndex, pin2); - adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.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/SimSmsTest.java similarity index 94% rename from tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java rename to tests/CoreTests/com/android/internal/telephony/SimSmsTest.java index 6ced23d7a4d626c597f91f7c49d1384cd1e10de4..1609680c0697badc044c408040d0da6b4235e492 100644 --- a/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java +++ b/tests/CoreTests/com/android/internal/telephony/SimSmsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.os.ServiceManager; import android.test.suitebuilder.annotation.MediumTest; @@ -33,7 +33,7 @@ public class SimSmsTest extends TestCase { ISms sms = ISms.Stub.asInterface(ServiceManager.getService("isms")); assertNotNull(sms); - List records = sms.getAllMessagesFromSimEf(); + List records = sms.getAllMessagesFromIccEf(); assertNotNull(records); assertTrue(records.size() >= 0); diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java similarity index 62% rename from tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java rename to tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java index 3fbc8f52f4e2f85eb4b8fd6ad379ba308da78c2f..e733af956178cfb160d4be844563e84b743db343 100644 --- a/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java +++ b/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import com.android.internal.telephony.gsm.SimTlv; -import com.android.internal.telephony.gsm.SimUtils; +import com.android.internal.telephony.IccUtils; import junit.framework.TestCase; import android.test.suitebuilder.annotation.SmallTest; @@ -33,46 +33,46 @@ public class SimUtilsTest extends TestCase { */ // An EF[ICCID] record - data = SimUtils.hexStringToBytes("981062400510444868f2"); - assertEquals("8901260450014484862", SimUtils.bcdToString(data, 0, data.length)); + data = IccUtils.hexStringToBytes("981062400510444868f2"); + assertEquals("8901260450014484862", IccUtils.bcdToString(data, 0, data.length)); // skip the first and last bytes - assertEquals("0126045001448486", SimUtils.bcdToString(data, 1, data.length - 2)); + assertEquals("0126045001448486", IccUtils.bcdToString(data, 1, data.length - 2)); // Stops on invalid BCD value - data = SimUtils.hexStringToBytes("98F062400510444868f2"); - assertEquals("890", SimUtils.bcdToString(data, 0, data.length)); + data = IccUtils.hexStringToBytes("98F062400510444868f2"); + assertEquals("890", IccUtils.bcdToString(data, 0, data.length)); /* * bcdByteToInt() */ - assertEquals(98, SimUtils.bcdByteToInt((byte) 0x89)); + assertEquals(98, IccUtils.bcdByteToInt((byte) 0x89)); // Out of range is treated as 0 - assertEquals(8, SimUtils.bcdByteToInt((byte) 0x8c)); + assertEquals(8, IccUtils.bcdByteToInt((byte) 0x8c)); /* * adnStringFieldToString() */ - data = SimUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff"); + data = IccUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff"); // Again, skip prepended 0 // (this is an EF[ADN] record) - assertEquals("Voice Mail", SimUtils.adnStringFieldToString(data, 1, data.length - 15)); + assertEquals("Voice Mail", IccUtils.adnStringFieldToString(data, 1, data.length - 15)); - data = SimUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF"); + data = IccUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF"); // (this is from an EF[ADN] record) - assertEquals("\u9673\u539A\u5764/M", SimUtils.adnStringFieldToString(data, 0, data.length)); + assertEquals("\u9673\u539A\u5764/M", IccUtils.adnStringFieldToString(data, 0, data.length)); - data = SimUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF"); + data = IccUtils.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)); + assertEquals("Vo\u00ECce M\u00E0il", IccUtils.adnStringFieldToString(data, 0, data.length)); - data = SimUtils.hexStringToBytes("820505302D82d32d31"); + data = IccUtils.hexStringToBytes("820505302D82d32d31"); // Example from 3GPP TS 11.11 V18.1.3.0 annex B - assertEquals("-\u0532\u0583-1", SimUtils.adnStringFieldToString(data, 0, data.length)); + assertEquals("-\u0532\u0583-1", IccUtils.adnStringFieldToString(data, 0, data.length)); } } diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java index eb2bd23ad7b417bfead66303b85c370999418514..b4fb32444a452cfe60b0e17d508cd5fec3f986ac 100644 --- a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java +++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java @@ -16,13 +16,13 @@ package com.android.internal.telephony; -import com.android.internal.telephony.gsm.AdnRecordTest; +import com.android.internal.telephony.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 com.android.internal.telephony.GsmAlphabetTest; +import com.android.internal.telephony.SMSDispatcherTest; +import com.android.internal.telephony.SimPhoneBookTest; +import com.android.internal.telephony.SimSmsTest; +import com.android.internal.telephony.SimUtilsTest; import junit.framework.TestSuite; diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml index 17c44adb9e3b87e40bbb6c16d30d9022d34f5a78..0e33d62ae5f14218ad571958c238fa62d8ec8406 100644 --- a/tests/DumpRenderTree/AndroidManifest.xml +++ b/tests/DumpRenderTree/AndroidManifest.xml @@ -31,4 +31,5 @@ android:targetPackage="com.android.dumprendertree" android:label="Layout test automation runner" /> + diff --git a/tests/DumpRenderTree/run_page_cycler.py b/tests/DumpRenderTree/assets/run_page_cycler.py similarity index 92% rename from tests/DumpRenderTree/run_page_cycler.py rename to tests/DumpRenderTree/assets/run_page_cycler.py index 9a099b52694b4a2f640b8c39cb6211511992bc83..2325047a1840e1ba4e7a52144441f4819431e8f3 100755 --- a/tests/DumpRenderTree/run_page_cycler.py +++ b/tests/DumpRenderTree/assets/run_page_cycler.py @@ -56,10 +56,11 @@ def main(options, args): run_load_test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner" # Call LoadTestsAutoTest::runTest. - run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix + run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runPageCyclerTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix (adb_output, adb_error) = subprocess.Popen(run_load_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() - if adb_output.find('INSTRUMENTATION_FAILED') != -1: + if adb_output.find('INSTRUMENTATION_FAILED') != -1 or \ + adb_output.find('Process crashed.') != -1: logging.error("Error happened : " + adb_output) sys.exit(1) diff --git a/tests/DumpRenderTree/assets/run_reliability_tests.py b/tests/DumpRenderTree/assets/run_reliability_tests.py new file mode 100755 index 0000000000000000000000000000000000000000..a2422938d68da93668fcada9a5ed739954ab86fd --- /dev/null +++ b/tests/DumpRenderTree/assets/run_reliability_tests.py @@ -0,0 +1,214 @@ +#!/usr/bin/python2.4 + +"""Run reliability tests using Android instrumentation. + + A test file consists of list web sites to test is needed as a parameter + + Usage: + run_reliability_tests.py path/to/url/list +""" + +import logging +import optparse +import random +import subprocess +import sys +import time + +TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt" +TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt" +TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt" +HTTP_URL_FILE = "urllist_http" +HTTPS_URL_FILE = "urllist_https" +NUM_URLS = 25 + + +def DumpRenderTreeFinished(adb_cmd): + """Check if DumpRenderTree finished running. + + Args: + adb_cmd: adb command string + + Returns: + True if DumpRenderTree has finished, False otherwise + """ + + # pull test status file and look for "#DONE" + shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE + adb_output = subprocess.Popen(shell_cmd_str, + shell=True, stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate()[0] + return adb_output.strip() == "#DONE" + + +def RandomPick(file_name, approx_size, num_needed): + """Randomly pick lines from the text file specifed. + + Args: + file_name: the text file where lines should be picked from + approx_size: an approximate size of the text file + num_needed: how many lines are needed from the file + + Returns: + an array of string + """ + p = float(num_needed) / approx_size + num_picked = 0 + lines = [] + random.seed() + + while num_picked < num_needed: + file_handle = open(file_name, "r") + for line in file_handle: + line = line.strip() + if float(random.randint(0, approx_size)) / approx_size < p: + lines.append(line) + num_picked += 1 + if num_picked == num_needed: + break + file_handle.close() + return lines + + +def main(options, args): + """Send the url list to device and start testing, restart if crashed.""" + + generate_url = False + + # Set up logging format. + log_level = logging.INFO + if options.verbose: + log_level = logging.DEBUG + logging.basicConfig(level=log_level, + format="%(message)s") + + # Include all tests if none are specified. + if not args: + path = "/tmp/url_list_%d.txt" % time.time() + generate_url = True + logging.info("A URL list is not provided, will be automatically generated.") + else: + path = args[0] + + if not options.crash_file: + print "missing crash file name, use --crash-file to specify" + sys.exit(1) + else: + crashed_file = options.crash_file + + if not options.timeout_file: + print "missing timeout file, use --timeout-file to specify" + sys.exit(1) + else: + timedout_file = options.timeout_file + + http = RandomPick(HTTP_URL_FILE, 500000, NUM_URLS) + https = RandomPick(HTTPS_URL_FILE, 45000, NUM_URLS) + + if generate_url: + file_handle = open(path, "w") + for i in range(0, NUM_URLS): + file_handle.write(http[i] + "\n") + file_handle.write(https[i] + "\n") + file_handle.close() + + adb_cmd = "adb " + if options.adb_options: + adb_cmd += options.adb_options + " " + + # push url list to device + test_cmd = adb_cmd + " push \"" + path + "\" \"" + TEST_LIST_FILE + "\"" + proc = subprocess.Popen(test_cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (adb_output, adb_error) = proc.communicate() + if proc.returncode != 0: + logging.error("failed to push url list to device.") + logging.error(adb_output) + logging.error(adb_error) + sys.exit(1) + + logging.info("Running the test ...") + + # Count crashed tests. + crashed_tests = [] + + if options.time_out_ms: + timeout_ms = options.time_out_ms + + # Run test until it's done + test_cmd_prefix = adb_cmd + " shell am instrument" + test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner" + + # Call ReliabilityTestsAutoTest#startReliabilityTests + test_cmd = (test_cmd_prefix + " -e class " + "com.android.dumprendertree.ReliabilityTestsAutoTest#" + "startReliabilityTests -e timeout " + timeout_ms + + test_cmd_postfix) + + time_start = time.time() + adb_output = subprocess.Popen(test_cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate()[0] + while not DumpRenderTreeFinished(adb_cmd): + logging.error("DumpRenderTree exited before all URLs are visited.") + shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE + crashed_test = subprocess.Popen(shell_cmd_str, shell=True, + stdout=subprocess.PIPE).communicate()[0] + logging.info(crashed_test + " CRASHED") + crashed_tests.append(crashed_test) + logging.info("Resuming reliability test runner...") + + test_cmd = (test_cmd_prefix + " -e class " + "com.android.dumprendertree.ReliabilityTestsAutoTest#" + "resumeReliabilityTests -e timeout " + timeout_ms + + test_cmd_postfix) + adb_output = subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate()[0] + + time_end = time.time() + fp = open("time_stat", "a") + fp.writelines("%.2f\n" % ((time_end - time_start) / NUM_URLS / 2)) + fp.close() + if (adb_output.find("INSTRUMENTATION_FAILED") != -1 or + adb_output.find("Process crashed.") != -1): + logging.error("Error happened : " + adb_output) + sys.exit(1) + + logging.info(adb_output) + logging.info("Done\n") + + if crashed_tests: + file_handle = open(crashed_file, "w") + file_handle.writelines("\n".join(crashed_tests)) + logging.info("Crashed URL list stored in: " + crashed_file) + file_handle.close() + else: + logging.info("No crash found.") + + test_cmd = (adb_cmd + "pull \"" + TEST_TIMEOUT_FILE + "\" \"" + + timedout_file + "\"") + + subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + + +if "__main__" == __name__: + option_parser = optparse.OptionParser() + option_parser.add_option("", "--time-out-ms", + default=60000, + help="set the timeout for each test") + option_parser.add_option("", "--verbose", action="store_true", + default=False, + help="include debug-level logging") + option_parser.add_option("", "--adb-options", + default=None, + help="pass options to adb, such as -d -e, etc") + option_parser.add_option("", "--crash-file", + default="reliability_crashed_sites.txt", + help="the list of sites that cause browser to crash") + option_parser.add_option("", "--timeout-file", + default="reliability_timedout_sites.txt", + help="the list of sites that timedout during test.") + opts, arguments = option_parser.parse_args() + main(opts, arguments) diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java index 39eae02940d2125fffe267dfb7f411278b3b57cf..caef86191c0ddbbfe177c27ca3313722432df2ea 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java @@ -16,24 +16,11 @@ package com.android.dumprendertree; -import android.app.Activity; import android.app.Instrumentation; -import android.app.Instrumentation.ActivityMonitor; -import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Intent; - -import android.util.Log; -import android.view.KeyEvent; -import android.webkit.WebSettings; - import android.os.Bundle; -import android.os.Message; import android.test.ActivityInstrumentationTestCase2; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; - -import com.android.dumprendertree.TestShellActivity; +import android.util.Log; import java.io.BufferedOutputStream; import java.io.BufferedReader; @@ -54,6 +41,7 @@ class MyTestRecorder { private BufferedOutputStream mBufferedOutputPassedStream; private BufferedOutputStream mBufferedOutputFailedStream; private BufferedOutputStream mBufferedOutputNoresultStream; + private BufferedOutputStream mBufferedOutputTimedoutStream; public void passed(String layout_file) { try { @@ -85,11 +73,22 @@ class MyTestRecorder { } } + public void timedout(String url) { + try { + mBufferedOutputTimedoutStream.write(url.getBytes()); + mBufferedOutputTimedoutStream.write('\n'); + mBufferedOutputTimedoutStream.flush(); + } catch (Exception e) { + e.printStackTrace(); + } + } + public MyTestRecorder(boolean resume) { try { File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt"); File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt"); File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt"); + File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt"); mBufferedOutputPassedStream = new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume)); @@ -97,6 +96,8 @@ class MyTestRecorder { new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume)); mBufferedOutputNoresultStream = new BufferedOutputStream(new FileOutputStream(noExpectedResultFile, resume)); + mBufferedOutputTimedoutStream = + new BufferedOutputStream(new FileOutputStream(resultTimedoutFile, resume)); } catch (Exception e) { e.printStackTrace(); } @@ -107,6 +108,7 @@ class MyTestRecorder { mBufferedOutputPassedStream.close(); mBufferedOutputFailedStream.close(); mBufferedOutputNoresultStream.close(); + mBufferedOutputTimedoutStream.close(); } catch (Exception e) { e.printStackTrace(); } @@ -141,6 +143,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2 mTestList; private boolean mRebaselineResults; private String mTestPathPrefix; + private boolean mFinished; public LayoutTestsAutoTest() { super("com.android.dumprendertree", TestShellActivity.class); @@ -290,9 +293,13 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2 0 ) { + while ((len = in.read(buf)) >= 0 ) { out.write(buf, 0, len); } out.close(); diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java index b064dbb404290bca217ccccb57057dc5feef041f..81cf3a8edf647b37ddc4c57d7c44dde1479823af 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java @@ -16,52 +16,34 @@ package com.android.dumprendertree; -import android.app.Activity; import android.app.Instrumentation; -import android.app.Instrumentation.ActivityMonitor; import android.content.Intent; import android.util.Log; import android.os.Bundle; +import android.os.Debug; +import android.os.Debug.MemoryInfo; import android.test.ActivityInstrumentationTestCase2; import com.android.dumprendertree.TestShellActivity; import com.android.dumprendertree.TestShellCallback; -import java.io.InputStream; -import java.io.OutputStream; import java.io.FileOutputStream; import java.io.IOException; - -class StreamPipe extends Thread { - InputStream in; - OutputStream out; - - StreamPipe(InputStream in, OutputStream out) { - this.in = in; - this.out = out; - } - - public void run() { - try { - byte[] buf = new byte[1024]; - int nofb = this.in.read(buf); - while (nofb != -1) { - this.out.write(buf, 0, nofb); - nofb = this.in.read(buf); - } - } catch (IOException e) { - e.printStackTrace(); - } - } -} +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2 { private final static String LOGTAG = "LoadTest"; private final static String LOAD_TEST_RESULT = "/sdcard/load_test_result.txt"; - + private boolean mFinished; + static final String LOAD_TEST_RUNNER_FILES[] = { + "run_page_cycler.py" + }; + public LoadTestsAutoTest() { super("com.android.dumprendertree", TestShellActivity.class); } @@ -74,17 +56,17 @@ public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2= 0 ) { + out.write(buf, 0, len); + } + out.close(); + in.close(); + } + }catch (IOException e) { + e.printStackTrace(); + } + + } + } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..347efde3f07f28bfaa120ec128d91afdb9ede14e --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java @@ -0,0 +1,209 @@ +package com.android.dumprendertree; + +import com.android.dumprendertree.TestShellActivity.DumpDataType; + +import android.content.Intent; +import android.test.ActivityInstrumentationTestCase2; +import android.util.Log; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.Vector; + +public class ReliabilityTestsAutoTest extends ActivityInstrumentationTestCase2 { + + private static final String LOGTAG = "ReliabilityTests"; + private static final String TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt"; + private static final String TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt"; + private static final String TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt"; + static final String RELIABILITY_TEST_RUNNER_FILES[] = { + "run_reliability_tests.py" + }; + + private boolean finished; + private List testList; + + public ReliabilityTestsAutoTest() { + super("com.android.dumprendertree", TestShellActivity.class); + } + + private void getTestList() { + // Read test list. + testList = new Vector(); + try { + BufferedReader inReader = new BufferedReader(new FileReader(TEST_LIST_FILE)); + String line; + while ((line = inReader.readLine()) != null) { + testList.add(line); + } + inReader.close(); + Log.v(LOGTAG, "Test list has " + testList.size() + " test(s)."); + } catch (Exception e) { + Log.e(LOGTAG, "Error while reading test list : " + e.getMessage()); + } + } + + private void resumeTestList() { + // read out the test name it stopped last time. + try { + BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE)); + String line = inReader.readLine(); + for (int i = 0; i < testList.size(); i++) { + if (testList.get(i).equals(line)) { + testList = new Vector(testList.subList(i+1, testList.size())); + break; + } + } + inReader.close(); + } catch (Exception e) { + Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE); + } + } + + private void clearTestStatus() { + // Delete TEST_STATUS_FILE + try { + File f = new File(TEST_STATUS_FILE); + if (f.delete()) + Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE); + else + Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE); + } catch (Exception e) { + Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage()); + } + } + + private void clearTestTimeout() { + // Delete TEST_TIMEOUT_FILE + try { + File f = new File(TEST_TIMEOUT_FILE); + if (f.delete()) + Log.v(LOGTAG, "Deleted " + TEST_TIMEOUT_FILE); + else + Log.e(LOGTAG, "Fail to delete " + TEST_TIMEOUT_FILE); + } catch (Exception e) { + Log.e(LOGTAG, "Fail to delete " + TEST_TIMEOUT_FILE + " : " + e.getMessage()); + } + } + + private void updateTestStatus(String s) { + // Write TEST_STATUS_FILE + try { + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE)); + bos.write(s.getBytes()); + bos.close(); + } catch (Exception e) { + Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE); + } + } + + private void writeTimeoutFile(String s) { + // Write TEST_TIMEOUT_FILE + try { + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_TIMEOUT_FILE, true)); + bos.write(s.getBytes()); + bos.write('\n'); + bos.close(); + } catch (Exception e) { + Log.e(LOGTAG, "Cannot update file " + TEST_TIMEOUT_FILE); + } + } + + private void runReliabilityTest(boolean resume) { + LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation(); + + getTestList(); + if(!resume) + clearTestStatus(); + else + resumeTestList(); + + TestShellActivity activity = getActivity(); + activity.setDefaultDumpDataType(DumpDataType.NO_OP); + // Run tests. + for (int i = 0; i < testList.size(); i++) { + String s = testList.get(i); + updateTestStatus(s); + // Run tests + runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis); + } + + updateTestStatus("#DONE"); + + activity.finish(); + } + + private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout) { + activity.setCallback(new TestShellCallback() { + public void finished() { + synchronized (ReliabilityTestsAutoTest.this) { + finished = true; + ReliabilityTestsAutoTest.this.notifyAll(); + } + } + + public void timedOut(String url) { + writeTimeoutFile(url); + } + }); + + finished = false; + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setClass(activity, TestShellActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + intent.putExtra(TestShellActivity.TEST_URL, url); + intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout); + activity.startActivity(intent); + + // Wait until done. + synchronized (this) { + while(!finished){ + try { + this.wait(); + } catch (InterruptedException e) { } + } + } + } + + public void startReliabilityTests() { + clearTestTimeout(); + runReliabilityTest(false); + } + + public void resumeReliabilityTests() { + runReliabilityTest(true); + } + + public void copyRunnerAssetsToCache() { + try { + String out_dir = getActivity().getApplicationContext() + .getCacheDir().getPath() + "/"; + + for( int i=0; i< RELIABILITY_TEST_RUNNER_FILES.length; i++) { + InputStream in = getActivity().getAssets().open( + RELIABILITY_TEST_RUNNER_FILES[i]); + OutputStream out = new FileOutputStream( + out_dir + RELIABILITY_TEST_RUNNER_FILES[i]); + + byte[] buf = new byte[2048]; + int len; + + while ((len = in.read(buf)) >= 0 ) { + out.write(buf, 0, len); + } + out.close(); + in.close(); + } + }catch (IOException e) { + e.printStackTrace(); + } + + } +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index bf8a3b35a443f3f9f54c3f0d65e28165f87159e4..1ba291c9c1349edd34bc7c1a6935a88f7229d07e 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -16,29 +16,40 @@ package com.android.dumprendertree; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Vector; - import android.app.Activity; import android.content.Intent; +import android.graphics.Bitmap; +import android.net.http.SslError; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.util.Log; +import android.view.ViewGroup; +import android.webkit.HttpAuthHandler; import android.webkit.JsPromptResult; import android.webkit.JsResult; -import android.view.ViewGroup; +import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; +import android.webkit.WebViewClient; import android.widget.LinearLayout; -import android.os.*; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Vector; public class TestShellActivity extends Activity implements LayoutTestController { + + static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP} + public class AsyncHandler extends Handler { @Override public void handleMessage(Message msg) { if (msg.what == MSG_TIMEOUT) { mTimedOut = true; + mCallback.timedOut(mWebView.getUrl()); requestWebKitData(); return; } else if (msg.what == MSG_WEBKIT_DATA) { @@ -57,10 +68,16 @@ public class TestShellActivity extends Activity implements LayoutTestController throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl()); mRequestedWebKitData = true; - if (mDumpAsText) { - mWebView.documentAsText(callback); - } else { - mWebView.externalRepresentation(callback); + switch (mDumpDataType) { + case DUMP_AS_TEXT: + mWebView.documentAsText(callback); + break; + case EXT_REPR: + mWebView.externalRepresentation(callback); + break; + default: + finished(); + break; } } @@ -75,6 +92,41 @@ public class TestShellActivity extends Activity implements LayoutTestController mWebView = new WebView(this); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.setWebChromeClient(mChromeClient); + mWebView.setWebViewClient(new WebViewClient(){ + + @Override + public void onPageFinished(WebView view, String url) { + Log.v(LOGTAG, "onPageFinished, url=" + url); + super.onPageFinished(view, url); + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + Log.v(LOGTAG, "onPageStarted, url=" + url); + super.onPageStarted(view, url, favicon); + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, + String failingUrl) { + Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode + + ", desc=" + description + ", url=" + failingUrl); + super.onReceivedError(view, errorCode, description, failingUrl); + } + + @Override + public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, + String host, String realm) { + handler.cancel(); + } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, + SslError error) { + handler.proceed(); + } + + }); mEventSender = new WebViewEventSender(mWebView); mCallbackProxy = new CallbackProxy(mEventSender, this); @@ -165,7 +217,8 @@ public class TestShellActivity extends Activity implements LayoutTestController if (mDialogStrings != null) os.write(mDialogStrings.toString().getBytes()); mDialogStrings = null; - os.write(webkitData.getBytes()); + if (webkitData != null) + os.write(webkitData.getBytes()); os.flush(); os.close(); } catch (IOException ex) { @@ -185,10 +238,14 @@ public class TestShellActivity extends Activity implements LayoutTestController } } + public void setDefaultDumpDataType(DumpDataType defaultDumpDataType) { + mDefaultDumpDataType = defaultDumpDataType; + } + // ....................................... // LayoutTestController Functions public void dumpAsText() { - mDumpAsText = true; + mDumpDataType = DumpDataType.DUMP_AS_TEXT; if (mWebView != null) { String url = mWebView.getUrl(); Log.v(LOGTAG, "dumpAsText called: "+url); @@ -381,7 +438,7 @@ public class TestShellActivity extends Activity implements LayoutTestController private void resetTestStatus() { mWaitUntilDone = false; - mDumpAsText = false; + mDumpDataType = mDefaultDumpDataType; mTimedOut = false; mDumpTitleChanges = false; mRequestedWebKitData = false; @@ -405,7 +462,8 @@ public class TestShellActivity extends Activity implements LayoutTestController private boolean mFinishedRunning; // Layout test controller variables. - private boolean mDumpAsText; + private DumpDataType mDumpDataType; + private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR; private boolean mWaitUntilDone; private boolean mDumpTitleChanges; private StringBuffer mTitleChanges; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java index 759c443392eb45db929a4ec7d487eb6863e0700a..55bf94742f847e1dc5ec5d69f3e26c9c7438e670 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java @@ -18,4 +18,5 @@ package com.android.dumprendertree; public interface TestShellCallback { public void finished(); + public void timedOut(String url); } diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java index 663b7a455d623ad70f706e945397fe8b1e88cb72..6f89fce71dd81264851ce0bc7630bad0d5be8090 100644 --- a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java +++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java @@ -147,4 +147,56 @@ public class AutoCompleteTextViewPopup // now try moving "down" - nothing should happen since there's no longer an adapter sendKeys("DPAD_DOWN"); } + + /** Test the show/hide behavior of the drop-down. */ + @MediumTest + public void testPopupShow() throws Throwable { + AutoCompleteTextViewSimple theActivity = getActivity(); + final AutoCompleteTextView textView = theActivity.getTextView(); + final Instrumentation instrumentation = getInstrumentation(); + + // Drop-down should not be showing when no text has been entered + assertFalse("isPopupShowing() on start", textView.isPopupShowing()); + + // focus and type + textView.requestFocus(); + instrumentation.waitForIdleSync(); + sendKeys("A"); + + // Drop-down should now be visible + assertTrue("isPopupShowing() after typing", textView.isPopupShowing()); + + // Clear the text + runTestOnUiThread(new Runnable() { + public void run() { + textView.setText(""); + } + }); + instrumentation.waitForIdleSync(); + + // Drop-down should be hidden when text is cleared + assertFalse("isPopupShowing() after text cleared", textView.isPopupShowing()); + + // Set the text, without filtering + runTestOnUiThread(new Runnable() { + public void run() { + textView.setText("a", false); + } + }); + instrumentation.waitForIdleSync(); + + // Drop-down should still be hidden + assertFalse("isPopupShowing() after setText(\"a\", false)", textView.isPopupShowing()); + + // Set the text, now with filtering + runTestOnUiThread(new Runnable() { + public void run() { + textView.setText("a"); + } + }); + instrumentation.waitForIdleSync(); + + // Drop-down should show up after setText() with filtering + assertTrue("isPopupShowing() after text set", textView.isPopupShowing()); + } } diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/SetTagsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/SetTagsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..523eeaf96f4830c64af9c19891a49fb2ed412891 --- /dev/null +++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/SetTagsTest.java @@ -0,0 +1,114 @@ +/* + * 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.frameworktest.view; + +import com.android.frameworktest.R; +import android.test.suitebuilder.annotation.MediumTest; + +import android.test.ActivityInstrumentationTestCase2; +import android.widget.Button; + +/** + * Exercises {@link android.view.View}'s tags property. + */ +public class SetTagsTest extends ActivityInstrumentationTestCase2 { + private Button mView; + + public SetTagsTest() { + super("com.android.frameworktest", Disabled.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + mView = (Button) getActivity().findViewById(R.id.disabledButton); + } + + @MediumTest + public void testSetUpConditions() throws Exception { + assertNotNull(mView); + } + + @MediumTest + public void testSetTag() throws Exception { + mView.setTag("1"); + } + + @MediumTest + public void testGetTag() throws Exception { + Object o = new Object(); + mView.setTag(o); + + final Object stored = mView.getTag(); + assertNotNull(stored); + assertSame("The stored tag is inccorect", o, stored); + } + + @MediumTest + public void testSetTagWithKey() throws Exception { + mView.setTag(R.id.a, "2"); + } + + @MediumTest + public void testGetTagWithKey() throws Exception { + Object o = new Object(); + mView.setTag(R.id.a, o); + + final Object stored = mView.getTag(R.id.a); + assertNotNull(stored); + assertSame("The stored tag is inccorect", o, stored); + } + + @MediumTest + public void testSetTagWithFrameworkId() throws Exception { + boolean result = false; + try { + mView.setTag(android.R.id.list, "2"); + } catch (IllegalArgumentException e) { + result = true; + } + assertTrue("Setting a tag with a framework id did not throw an exception", result); + } + + @MediumTest + public void testSetTagWithNoPackageId() throws Exception { + boolean result = false; + try { + mView.setTag(0x000000AA, "2"); + } catch (IllegalArgumentException e) { + result = true; + } + assertTrue("Setting a tag with an id with no package did not throw an exception", result); + } + + @MediumTest + public void testSetTagInternalWithFrameworkId() throws Exception { + mView.setTagInternal(android.R.id.list, "2"); + } + + @MediumTest + public void testSetTagInternalWithApplicationId() throws Exception { + boolean result = false; + try { + mView.setTagInternal(R.id.a, "2"); + } catch (IllegalArgumentException e) { + result = true; + } + assertTrue("Setting a tag with an id with app package did not throw an exception", result); + } +} diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..2e3385f8b569e4e49d5e1629b085d4c3ff005faa --- /dev/null +++ b/tests/backup/Android.mk @@ -0,0 +1,41 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +# native test +# ======================================== +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + backup_helper_test.cpp + +LOCAL_MODULE_TAGS := user +LOCAL_MODULE := backup_helper_test +LOCAL_SHARED_LIBRARIES := libutils + +include $(BUILD_EXECUTABLE) + +# java test +# ======================================== +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := user + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := BackupTest + +include $(BUILD_PACKAGE) + diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..eaeb5b72da94fbf4b962c14d66479a217b28c7b6 --- /dev/null +++ b/tests/backup/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/tests/backup/backup_helper_test.cpp b/tests/backup/backup_helper_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6da16b4de4c948a64dc0de803758dd97af22a9c5 --- /dev/null +++ b/tests/backup/backup_helper_test.cpp @@ -0,0 +1,104 @@ +#include + +#include +#include + +#if TEST_BACKUP_HELPERS + +// ============================================================ +// ============================================================ +typedef int (*test_func)(); + +struct Test { + const char* name; + test_func func; + int result; + bool run; +}; + +Test TESTS[] = { + { "backup_helper_test_empty", backup_helper_test_empty, 0, false }, + { "backup_helper_test_four", backup_helper_test_four, 0, false }, + { "backup_helper_test_files", backup_helper_test_files, 0, false }, + { 0, NULL, 0, false} +}; + +int +main(int argc, const char** argv) +{ + Test* t; + + if (argc == 1) { + t = TESTS; + while (t->name) { + t->run = true; + t++; + } + } else { + t = TESTS; + while (t->name) { + for (int i=1; iname, argv[i])) { + t->run = true; + } + } + t++; + } + } + + int testCount = 0; + t = TESTS; + while (t->name) { + if (t->run) { + testCount++; + } + t++; + } + + + int failed = 0; + int i = 1; + t = TESTS; + while (t->name) { + if (t->run) { + printf("===== Running %s (%d of %d) ==============================\n", + t->name, i, testCount); + fflush(stdout); + fflush(stderr); + t->result = t->func(); + if (t->result != 0) { + failed++; + printf("failed\n"); + } else { + printf("passed\n"); + } + i++; + } + t++; + } + + printf("=================================================================\n"); + if (failed == 0) { + printf("All %d test(s) passed\n", testCount); + } else { + printf("Tests failed: (%d of %d)\n", failed, testCount); + t = TESTS; + while (t->name) { + if (t->run) { + if (t->result != 0) { + printf(" %s\n", t->name); + } + } + t++; + } + } +} + +#else +int +main(int argc, char** argv) +{ + printf ("test_backup_helper built without the tests\n"); + return 0; +} +#endif diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..af7dfd4c191540058fdc85d448227074c62d8592 --- /dev/null +++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.backuptest; + +import android.app.ListActivity; +import android.backup.BackupManager; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.PowerManager; +import android.os.SystemClock; +import android.util.Log; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.Toast; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintStream; +import java.text.DateFormat; +import java.util.Date; + +public class BackupTestActivity extends ListActivity +{ + static final String TAG = "BackupTestActivity"; + + static final String PREF_GROUP_SETTINGS = "settings"; + static final String PREF_KEY = "pref"; + static final String FILE_NAME = "file.txt"; + + Test[] mTests = new Test[] { + new Test("Show File") { + void run() { + StringBuffer str = new StringBuffer(); + str.append("Text is:"); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(openFileInput(FILE_NAME))); + while (reader.ready()) { + str.append("\n"); + str.append(reader.readLine()); + } + } catch (IOException ex) { + str.append("ERROR: "); + str.append(ex.toString()); + } + Log.d(TAG, str.toString()); + Toast.makeText(BackupTestActivity.this, str, Toast.LENGTH_SHORT).show(); + } + }, + new Test("Append to File") { + void run() { + PrintStream output = null; + try { + output = new PrintStream(openFileOutput(FILE_NAME, MODE_APPEND)); + DateFormat formatter = DateFormat.getDateTimeInstance(); + output.println(formatter.format(new Date())); + output.close(); + } catch (IOException ex) { + if (output != null) { + output.close(); + } + } + BackupManager bm = new BackupManager(BackupTestActivity.this); + bm.dataChanged(); + } + }, + new Test("Clear File") { + void run() { + PrintStream output = null; + try { + output = new PrintStream(openFileOutput(FILE_NAME, MODE_PRIVATE)); + output.close(); + } catch (IOException ex) { + if (output != null) { + output.close(); + } + } + BackupManager bm = new BackupManager(BackupTestActivity.this); + bm.dataChanged(); + } + }, + new Test("Poke") { + void run() { + BackupManager bm = new BackupManager(BackupTestActivity.this); + bm.dataChanged(); + } + }, + new Test("Show Shared Pref") { + void run() { + SharedPreferences prefs = getSharedPreferences(PREF_GROUP_SETTINGS, MODE_PRIVATE); + int val = prefs.getInt(PREF_KEY, 0); + String str = "'" + PREF_KEY + "' is " + val; + Log.d(TAG, str); + Toast.makeText(BackupTestActivity.this, str, Toast.LENGTH_SHORT).show(); + } + }, + new Test("Increment Shared Pref") { + void run() { + SharedPreferences prefs = getSharedPreferences(PREF_GROUP_SETTINGS, MODE_PRIVATE); + int val = prefs.getInt(PREF_KEY, 0); + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(PREF_KEY, val+1); + editor.commit(); + BackupManager bm = new BackupManager(BackupTestActivity.this); + bm.dataChanged(); + } + } + }; + + abstract class Test { + String name; + Test(String n) { + name = n; + } + abstract void run(); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + String[] labels = new String[mTests.length]; + for (int i=0; i(this, android.R.layout.simple_list_item_1, labels)); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) + { + Test t = mTests[position]; + Log.d(TAG, "Test: " + t.name); + t.run(); + } + +} + diff --git a/tests/backup/src/com/android/backuptest/BackupTestService.java b/tests/backup/src/com/android/backuptest/BackupTestService.java new file mode 100644 index 0000000000000000000000000000000000000000..00eb86e47a743c76ee778f9892cc63d69652f6bc --- /dev/null +++ b/tests/backup/src/com/android/backuptest/BackupTestService.java @@ -0,0 +1,43 @@ +/* + * 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.backuptest; + +import android.backup.BackupService; +import android.backup.BackupDataOutput; +import android.backup.FileBackupHelper; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +public class BackupTestService extends BackupService +{ + static final String TAG = "BackupTestService"; + + @Override + public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState) { + Log.d(TAG, "onBackup"); + FileBackupHelper.performBackup(this, oldState, data, newState, new String[] { + BackupTestActivity.FILE_NAME + }); + } + + @Override + public void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) { + Log.d(TAG, "onRestore"); + } +} + diff --git a/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java index 0368651863149c6783b0d4cdb8278e3b4fc6d08e..fd05fed2e07ffcb65659611f761398affd94a14c 100644 --- a/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java +++ b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java @@ -17,8 +17,7 @@ package com.android.internal.policy.impl; import android.content.Context; - -import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.IccCard; import android.test.AndroidTestCase; import android.view.View; import android.view.KeyEvent; @@ -39,7 +38,7 @@ public class LockPatternKeyguardViewTest extends AndroidTestCase { private static class MockUpdateMonitor extends KeyguardUpdateMonitor { - public SimCard.State simState = SimCard.State.READY; + public IccCard.State simState = IccCard.State.READY; public boolean inPortrait = false; public boolean keyboardOpen = false; @@ -48,7 +47,7 @@ public class LockPatternKeyguardViewTest extends AndroidTestCase { } @Override - public SimCard.State getSimState() { + public IccCard.State getSimState() { return simState; } @@ -339,7 +338,7 @@ public class LockPatternKeyguardViewTest extends AndroidTestCase { public void testMenuDoesntGoToUnlockScreenOnWakeWhenPukLocked() { // PUK locked - mUpdateMonitor.simState = SimCard.State.PUK_REQUIRED; + mUpdateMonitor.simState = IccCard.State.PUK_REQUIRED; // wake by menu mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU); diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index a09b1a65bb955e6bbb7ca5637a6994ac37a72803..ef11a83c83875f4236bc16bbbd9c4d78ee53c52f 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -1225,7 +1225,7 @@ status_t compileResourceFile(Bundle* bundle, // pseudolocalize here block.setPosition(parserPosition); err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, - ident, *curTag, curIsStyled, curFormat, true, false, outTable); + ident, *curTag, curIsStyled, curFormat, true, overwrite, outTable); if (err != NO_ERROR) { hasErrors = localHasErrors = true; } diff --git a/tools/layoutlib/.gitignore b/tools/layoutlib/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d44a17d9f80ddc222e31d59ad46676ceb546d96b --- /dev/null +++ b/tools/layoutlib/.gitignore @@ -0,0 +1,3 @@ +api/bin +bridge/bin +create/bin diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java index 727d6f24bb3ab1e1229d99b9019c40175758b2a7..cfab90a94b3a2af4a8966d2b677cdba3134d77f8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java @@ -17,7 +17,6 @@ package com.android.layoutlib.bridge; import android.content.ContentResolver; -import android.content.ContentServiceNative; import android.content.Context; import android.content.IContentProvider; import android.database.ContentObserver; @@ -51,9 +50,6 @@ public class BridgeContentResolver extends ContentResolver { /** * Stub for the layoutlib bridge content resolver. - *

          - * The super implementation accesses the {@link ContentServiceNative#getDefault()} - * which returns null and would make the call crash. Instead we do nothing. */ @Override public void registerContentObserver(Uri uri, boolean notifyForDescendents, @@ -63,9 +59,6 @@ public class BridgeContentResolver extends ContentResolver { /** * Stub for the layoutlib bridge content resolver. - *

          - * The super implementation accesses the {@link ContentServiceNative#getDefault()} - * which returns null and would make the call crash. Instead we do nothing. */ @Override public void unregisterContentObserver(ContentObserver observer) { @@ -74,9 +67,6 @@ public class BridgeContentResolver extends ContentResolver { /** * Stub for the layoutlib bridge content resolver. - *

          - * The super implementation accesses the {@link ContentServiceNative#getDefault()} - * which returns null and would make the call crash. Instead we do nothing. */ @Override public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { @@ -85,9 +75,6 @@ public class BridgeContentResolver extends ContentResolver { /** * Stub for the layoutlib bridge content resolver. - *

          - * The super implementation accesses the {@link ContentServiceNative#getDefault()} - * which returns null and would make the call crash. Instead we do nothing. */ @Override public void startSync(Uri uri, Bundle extras) { @@ -96,9 +83,6 @@ public class BridgeContentResolver extends ContentResolver { /** * Stub for the layoutlib bridge content resolver. - *

          - * The super implementation accesses the {@link ContentServiceNative#getDefault()} - * which returns null and would make the call crash. Instead we do nothing. */ @Override public void cancelSync(Uri uri) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java index baa3d53106efe0ef6f78867c07ee3f5ee755f16f..f434e14e5968f149629b837ab2116fc1057419cf 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java @@ -1145,4 +1145,12 @@ public final class BridgeContext extends Context { public Context getApplicationContext() { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public float getApplicationScale() { + throw new UnsupportedOperationException(); + } } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index f9a0845f12eaaf6e40f431643166c1544f899072..00829d6deedc8a82048b03e744688a16e24159bd 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -69,5 +69,11 @@ interface IWifiManager boolean acquireWifiLock(IBinder lock, int lockType, String tag); boolean releaseWifiLock(IBinder lock); + + boolean isWifiMulticastEnabled(); + + void enableWifiMulticast(IBinder binder, String tag); + + void disableWifiMulticast(); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index a51e88f978e93739b3df81e993c7aa274b9b44c1..658a7b24805b46981a990f057835f114b87ef595 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -823,4 +823,65 @@ public class WifiManager { public WifiLock createWifiLock(String tag) { return new WifiLock(WIFI_MODE_FULL, tag); } + + /** + * Check multicast filter status. + * + * @return true if multicast packets are allowed. + * + * @hide pending API council approval + */ + public boolean isWifiMulticastEnabled() { + try { + return mService.isWifiMulticastEnabled(); + } catch (RemoteException e) { + return false; + } + } + + /** + * Turn on the reception of multicast packets. + * The default behavior is to disable multicast packets as they + * have a noticable negative effect on battery life. An + * application can turn them on, but should not leave it on for longer + * than needed. When the app quits (or crashes) its request will + * be reverted. + * + * @param tag a string associated with this request for debugging. + * + * @return true on success + * + * @see #disableWifiMulticast + * + * @hide pending API council approval + */ + public boolean enableWifiMulticast(String tag) { + try { + mService.enableWifiMulticast(new Binder(), tag); + return true; + } catch (RemoteException e) { + return false; + } + } + + /** + * Return to the default multicast-off setting. + * Note that if others had turned on Multicast reception, your + * call will not turn it back off - they must also turn off their + * request for multicast reception. + * + * @return true on success + * + * @see #enableWifiMulticast + * + * @hide pending API council approval + */ + public boolean disableWifiMulticast() { + try { + mService.disableWifiMulticast(); + return true; + } catch (RemoteException e) { + return false; + } + } } diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 6ea35f58be028b3f42e801eb3fa089184696bc32..64084cf403c30ee35ad926f579be97ed2359eed9 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -732,15 +732,19 @@ public class WifiStateTracker extends NetworkStateTracker { /* * Filter out multicast packets. This saves battery power, since * the CPU doesn't have to spend time processing packets that - * are going to end up being thrown away. Obviously, if we - * ever want to support multicast, this will have to change. + * are going to end up being thrown away. + * + * Note that rather than turn this off directly, we use the + * public api - this keeps us all in sync - turn multicast on + * first and then off.. if nobody else wants it on it'll be + * off then and it's all synchronized within the API. */ + mWM.enableWifiMulticast("WifiStateTracker"); + mWM.disableWifiMulticast(); + if (mBluetoothA2dp == null) { mBluetoothA2dp = new BluetoothA2dp(mContext); } - synchronized (this) { - WifiNative.startPacketFiltering(); - } checkIsBluetoothPlaying(); break;