summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.xml947
-rw-r--r--awt/com/android/internal/awt/AndroidGraphics2D.java4
-rw-r--r--camera/libcameraservice/Android.mk10
-rw-r--r--camera/libcameraservice/CameraService.cpp60
-rw-r--r--camera/libcameraservice/CameraService.h2
-rw-r--r--camera/tests/CameraServiceTest/Android.mk12
-rwxr-xr-xcmds/am/am1
-rwxr-xr-xcmds/bmgr/bmgr1
-rw-r--r--cmds/bootanimation/Android.mk8
-rwxr-xr-xcmds/ime/ime1
-rw-r--r--cmds/installd/commands.c156
-rw-r--r--cmds/installd/installd.h1
-rwxr-xr-xcmds/pm/pm1
-rw-r--r--cmds/zipalign/Android.mk25
-rw-r--r--core/java/android/app/ApplicationErrorReport.java2
-rw-r--r--core/java/android/app/ContextImpl.java5
-rw-r--r--core/java/android/app/NotificationManager.java23
-rw-r--r--core/java/android/bluetooth/BluetoothClass.java8
-rw-r--r--core/java/android/bluetooth/BluetoothHid.java279
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java8
-rw-r--r--core/java/android/bluetooth/IBluetoothHid.aidl32
-rwxr-xr-x[-rw-r--r--]core/java/android/content/res/Resources.java142
-rw-r--r--core/java/android/hardware/Camera.java347
-rw-r--r--core/java/android/hardware/CameraSwitch.java80
-rw-r--r--core/java/android/hardware/HtcFrontFacingCamera.java14
-rw-r--r--core/java/android/net/ConnectivityManager.java3
-rw-r--r--core/java/android/net/NetworkInfo.java9
-rw-r--r--core/java/android/net/Proxy.java80
-rw-r--r--core/java/android/net/http/Connection.java65
-rw-r--r--core/java/android/net/http/ConnectionThread.java36
-rw-r--r--core/java/android/net/http/Headers.java9
-rw-r--r--core/java/android/net/http/Request.java7
-rw-r--r--core/java/android/net/http/RequestFeeder.java2
-rw-r--r--core/java/android/net/http/RequestHandle.java2
-rw-r--r--core/java/android/net/http/RequestQueue.java139
-rw-r--r--core/java/android/os/Debug.java17
-rw-r--r--core/java/android/os/IPowerManager.aidl7
-rw-r--r--core/java/android/preference/ListPreference.java48
-rw-r--r--core/java/android/provider/Browser.java29
-rw-r--r--core/java/android/provider/Settings.java583
-rw-r--r--core/java/android/provider/Telephony.java4
-rw-r--r--core/java/android/server/BluetoothA2dpService.java43
-rw-r--r--core/java/android/server/BluetoothEventLoop.java19
-rw-r--r--core/java/android/server/BluetoothHidService.java462
-rw-r--r--core/java/android/server/BluetoothService.java10
-rw-r--r--core/java/android/text/Layout.java51
-rw-r--r--core/java/android/text/SpannableStringBuilder.java6
-rw-r--r--core/java/android/text/StaticLayout.java16
-rw-r--r--core/java/android/text/Styled.java8
-rw-r--r--core/java/android/text/format/Time.java90
-rw-r--r--core/java/android/view/HapticFeedbackConstants.java6
-rw-r--r--core/java/android/view/KeyEvent.java11
-rw-r--r--core/java/android/view/RawInputEvent.java1
-rw-r--r--core/java/android/view/ViewRoot.java3
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java90
-rw-r--r--core/java/android/webkit/BrowserFrame.java25
-rw-r--r--core/java/android/webkit/DnsResolver.java206
-rw-r--r--core/java/android/webkit/HTML5VideoViewProxy.java2
-rw-r--r--core/java/android/webkit/LoadListener.java37
-rw-r--r--core/java/android/webkit/Network.java24
-rw-r--r--core/java/android/webkit/WebSettings.java8
-rw-r--r--core/java/android/webkit/WebView.java43
-rw-r--r--core/java/android/webkit/WebViewCore.java16
-rw-r--r--core/java/android/widget/TabHost.java26
-rw-r--r--core/java/android/widget/TextView.java2
-rw-r--r--core/java/com/android/internal/app/AlertController.java1
-rw-r--r--core/java/com/android/internal/app/ShutdownThread.java47
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java12
-rw-r--r--core/java/com/android/internal/os/SamplingProfilerIntegration.java3
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java86
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java82
-rw-r--r--core/java/com/google/android/mms/pdu/PduParser.java94
-rw-r--r--core/jni/Android.mk9
-rw-r--r--core/jni/AndroidRuntime.cpp15
-rw-r--r--core/jni/CursorWindow.cpp19
-rw-r--r--core/jni/CursorWindow.h12
-rw-r--r--core/jni/android/graphics/Canvas.cpp2
-rw-r--r--core/jni/android_hardware_Camera.cpp3
-rw-r--r--core/jni/android_net_NetUtils.cpp25
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp54
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp15
-rw-r--r--core/jni/android_server_BluetoothHidService.cpp335
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock.xml64
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock_land.xml60
-rw-r--r--core/res/res/layout/keyguard_screen_unlock_landscape.xml7
-rw-r--r--core/res/res/layout/keyguard_screen_unlock_portrait.xml11
-rw-r--r--core/res/res/layout/recent_apps_dialog.xml1
-rw-r--r--core/res/res/layout/recent_apps_dialog_12.xml129
-rw-r--r--core/res/res/layout/recent_apps_dialog_15.xml141
-rw-r--r--core/res/res/layout/recent_apps_icon_12.xml40
-rw-r--r--core/res/res/layout/recent_apps_icon_15.xml40
-rw-r--r--core/res/res/layout/status_bar_expanded.xml2
-rw-r--r--core/res/res/layout/status_bar_tracking.xml2
-rw-r--r--core/res/res/values-de/strings.xml15
-rw-r--r--core/res/res/values-he-rIL/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-it/strings.xml7
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values/arrays.xml3
-rw-r--r--core/res/res/values/attrs.xml9
-rw-r--r--core/res/res/values/config.xml6
-rw-r--r--core/res/res/values/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values/strings.xml15
-rw-r--r--core/tests/coretests/src/android/preference/ListPreferenceTest.java45
-rw-r--r--docs/html/resources/articles/painless-threading.jd2
-rw-r--r--graphics/java/android/graphics/ArabicReshape.java448
-rw-r--r--graphics/java/android/graphics/Canvas.java436
-rw-r--r--graphics/java/android/graphics/Color.java2
-rw-r--r--graphics/java/android/graphics/Paint.java25
-rw-r--r--graphics/jni/Android.mk8
-rw-r--r--include/binder/MemoryDealer.h5
-rw-r--r--include/binder/MemoryDealerEclair.h257
-rw-r--r--include/binder/MemoryHeapPmem.h10
-rw-r--r--include/camera/CameraParameters.h53
-rw-r--r--include/media/AudioRecord.h6
-rw-r--r--include/media/IMediaRecorder.h1
-rw-r--r--include/media/MediaPlayerInterface.h1
-rw-r--r--include/media/MediaProfiles.h5
-rw-r--r--include/media/MediaRecorderBase.h1
-rw-r--r--include/media/PVMediaRecorder.h1
-rw-r--r--include/media/mediarecorder.h1
-rw-r--r--include/ui/EventHub.h3
-rw-r--r--include/ui/KeycodeLabels.h20
-rw-r--r--include/ui/Overlay.h2
-rw-r--r--include/utils/Asset.h6
-rw-r--r--libs/audioflinger/Android.mk1
-rw-r--r--libs/audioflinger/AudioDSP.cpp651
-rw-r--r--libs/audioflinger/AudioDSP.h173
-rw-r--r--libs/audioflinger/AudioFlinger.cpp10
-rw-r--r--libs/audioflinger/AudioFlinger.h7
-rw-r--r--libs/audioflinger/AudioMixer.cpp263
-rw-r--r--libs/audioflinger/AudioMixer.h33
-rw-r--r--libs/binder/Android.mk8
-rw-r--r--libs/binder/MemoryDealerEclair.cpp422
-rw-r--r--libs/binder/MemoryHeapPmem.cpp4
-rw-r--r--libs/camera/Android.mk12
-rw-r--r--libs/camera/CameraParameters.cpp64
-rw-r--r--libs/surfaceflinger/Android.mk8
-rw-r--r--libs/surfaceflinger/Layer.cpp12
-rw-r--r--libs/surfaceflinger/LayerBase.cpp60
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp39
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h11
-rw-r--r--libs/surfaceflinger_client/Android.mk11
-rw-r--r--libs/ui/Android.mk21
-rw-r--r--libs/ui/EventHub.cpp5
-rw-r--r--libs/ui/Overlay.cpp7
-rw-r--r--libs/utils/ResourceTypes.cpp2
-rw-r--r--location/java/android/location/Address.java6
-rw-r--r--media/java/android/media/AudioManager.java7
-rw-r--r--media/java/android/media/CamcorderProfile.java8
-rw-r--r--media/java/android/media/EncoderCapabilities.java1
-rw-r--r--media/java/android/media/MediaFile.java4
-rw-r--r--media/java/android/media/MediaRecorder.java5
-rw-r--r--media/java/android/media/Ringtone.java3
-rw-r--r--media/jni/Android.mk10
-rw-r--r--media/jni/android_media_MediaProfiles.cpp2
-rw-r--r--media/jni/android_media_MediaRecorder.cpp24
-rw-r--r--media/libmedia/Android.mk8
-rw-r--r--media/libmedia/AudioRecord.cpp4
-rw-r--r--media/libmedia/AudioTrack.cpp4
-rw-r--r--media/libmedia/IMediaRecorder.cpp17
-rw-r--r--media/libmedia/MediaProfiles.cpp5
-rw-r--r--media/libmedia/mediarecorder.cpp22
-rw-r--r--media/libmediaplayerservice/Android.mk13
-rw-r--r--media/libmediaplayerservice/FLACPlayer.cpp577
-rw-r--r--media/libmediaplayerservice/FLACPlayer.h100
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp9
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp10
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.h1
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp42
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.h5
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp4
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h1
-rw-r--r--media/libstagefright/Android.mk14
-rw-r--r--media/libstagefright/OMXCodec.cpp5
-rw-r--r--media/libstagefright/StagefrightMediaScanner.cpp80
-rw-r--r--media/libstagefright/colorconversion/Android.mk10
-rw-r--r--media/libstagefright/omx/tests/OMXHarness.cpp8
-rw-r--r--opengl/libs/EGL/egl.cpp4
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/OpenvpnService.java423
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java2
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnService.java46
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java8
-rw-r--r--services/java/com/android/server/ConnectivityService.java6
-rw-r--r--services/java/com/android/server/InputDevice.java280
-rw-r--r--services/java/com/android/server/KeyInputQueue.java117
-rw-r--r--services/java/com/android/server/LightsService.java24
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java270
-rw-r--r--services/java/com/android/server/PackageManagerService.java4
-rw-r--r--services/java/com/android/server/PowerManagerService.java388
-rw-r--r--services/java/com/android/server/ProcessStats.java32
-rw-r--r--services/java/com/android/server/SystemServer.java8
-rw-r--r--services/java/com/android/server/ThrottleService.java7
-rwxr-xr-xservices/java/com/android/server/VibratorService.java17
-rw-r--r--services/java/com/android/server/WindowManagerService.java121
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java55
-rw-r--r--services/java/com/android/server/am/AppWaitingForDebuggerDialog.java3
-rw-r--r--services/java/com/android/server/am/FactoryErrorDialog.java4
-rw-r--r--services/java/com/android/server/status/IconData.java67
-rw-r--r--services/java/com/android/server/status/StatusBarIcon.java93
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java62
-rw-r--r--services/java/com/android/server/status/StatusBarService.java188
-rw-r--r--services/java/com/android/server/status/TickerView.java21
-rw-r--r--services/java/com/android/server/status/TrackingPatternView.java27
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java35
-rw-r--r--telephony/java/com/android/internal/telephony/AdnRecordCache.java19
-rw-r--r--telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java3
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java3
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SIMRecords.java7
-rwxr-xr-x[-rw-r--r--]telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java25
-rw-r--r--tests/CoreTests/android/AndroidManifest.xml1
-rw-r--r--tests/CoreTests/android/core/HttpHeaderTest.java62
-rw-r--r--tests/CoreTests/android/core/ProxyTest.java93
-rw-r--r--tools/aapt/ResourceTable.cpp46
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas.java56
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java2
-rw-r--r--vpn/java/android/net/vpn/OpenvpnProfile.java251
-rw-r--r--vpn/java/android/net/vpn/VpnManager.java2
-rw-r--r--vpn/java/android/net/vpn/VpnType.java3
-rw-r--r--wifi/java/android/net/wifi/WifiNative.java6
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java73
222 files changed, 11996 insertions, 1082 deletions
diff --git a/Android.mk b/Android.mk
index 6e1bdc5..df7d8a0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -100,6 +100,7 @@ LOCAL_SRC_FILES += \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
core/java/android/bluetooth/IBluetoothCallback.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
+ core/java/android/bluetooth/IBluetoothHid.aidl \
core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/content/IContentService.aidl \
core/java/android/content/IIntentReceiver.aidl \
diff --git a/api/current.xml b/api/current.xml
index 9d259f3..4a8ecb7 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -29016,6 +29016,50 @@
visibility="public"
>
</field>
+<field name="PERIPHERAL_COMBO_KEYBORD_POINTING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1472"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PERIPHERAL_KEYBORD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1344"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PERIPHERAL_POINTING_DEVICE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1408"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PERIPHERAL_UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1280"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="PHONE_CELLULAR"
type="int"
transient="false"
@@ -59431,7 +59475,7 @@
<method name="drawText"
return="void"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -71548,6 +71592,19 @@
visibility="public"
>
</method>
+<method name="open"
+ return="android.hardware.Camera"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cameraNode" type="java.lang.String">
+</parameter>
+</method>
<method name="reconnect"
return="void"
abstract="false"
@@ -71908,6 +71965,28 @@
visibility="public"
>
</method>
+<method name="getAutoExposure"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getBrightness"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getColorEffect"
return="java.lang.String"
abstract="false"
@@ -71919,6 +71998,61 @@
visibility="public"
>
</method>
+<method name="getContrast"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDefaultBrightness"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDefaultContrast"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDefaultSaturation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDefaultSharpness"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getExposureCompensation"
return="int"
abstract="false"
@@ -71985,6 +72119,17 @@
visibility="public"
>
</method>
+<method name="getISOValue"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getInt"
return="int"
abstract="false"
@@ -72031,6 +72176,39 @@
visibility="public"
>
</method>
+<method name="getLensShade"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxBrightness"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxContrast"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getMaxExposureCompensation"
return="int"
abstract="false"
@@ -72042,6 +72220,28 @@
visibility="public"
>
</method>
+<method name="getMaxSaturation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxSharpness"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getMaxZoom"
return="int"
abstract="false"
@@ -72119,6 +72319,17 @@
visibility="public"
>
</method>
+<method name="getSaturation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSceneMode"
return="java.lang.String"
abstract="false"
@@ -72130,6 +72341,17 @@
visibility="public"
>
</method>
+<method name="getSharpness"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSupportedAntibanding"
return="java.util.List&lt;java.lang.String&gt;"
abstract="false"
@@ -72141,6 +72363,17 @@
visibility="public"
>
</method>
+<method name="getSupportedAutoexposure"
+ return="java.util.List&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSupportedColorEffects"
return="java.util.List&lt;java.lang.String&gt;"
abstract="false"
@@ -72174,6 +72407,17 @@
visibility="public"
>
</method>
+<method name="getSupportedIsoValues"
+ return="java.util.List&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSupportedJpegThumbnailSizes"
return="java.util.List&lt;android.hardware.Camera.Size&gt;"
abstract="false"
@@ -72185,6 +72429,17 @@
visibility="public"
>
</method>
+<method name="getSupportedLensShadeModes"
+ return="java.util.List&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSupportedPictureFormats"
return="java.util.List&lt;java.lang.Integer&gt;"
abstract="false"
@@ -72306,6 +72561,17 @@
visibility="public"
>
</method>
+<method name="isSmartContrastEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isSmoothZoomSupported"
return="boolean"
abstract="false"
@@ -72395,6 +72661,32 @@
<parameter name="antibanding" type="java.lang.String">
</parameter>
</method>
+<method name="setAutoExposure"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
+<method name="setBrightness"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="brightness" type="float">
+</parameter>
+</method>
<method name="setColorEffect"
return="void"
abstract="false"
@@ -72408,6 +72700,19 @@
<parameter name="value" type="java.lang.String">
</parameter>
</method>
+<method name="setContrast"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="contrast" type="float">
+</parameter>
+</method>
<method name="setExposureCompensation"
return="void"
abstract="false"
@@ -72512,6 +72817,19 @@
<parameter name="timestamp" type="long">
</parameter>
</method>
+<method name="setISOValue"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="iso" type="java.lang.String">
+</parameter>
+</method>
<method name="setJpegQuality"
return="void"
abstract="false"
@@ -72553,6 +72871,19 @@
<parameter name="height" type="int">
</parameter>
</method>
+<method name="setLensShade"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="lensshade" type="java.lang.String">
+</parameter>
+</method>
<method name="setPictureFormat"
return="void"
abstract="false"
@@ -72635,6 +72966,19 @@
<parameter name="rotation" type="int">
</parameter>
</method>
+<method name="setSaturation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="saturation" type="float">
+</parameter>
+</method>
<method name="setSceneMode"
return="void"
abstract="false"
@@ -72648,6 +72992,32 @@
<parameter name="value" type="java.lang.String">
</parameter>
</method>
+<method name="setSharpness"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sharpness" type="float">
+</parameter>
+</method>
+<method name="setSmartContrastEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
<method name="setWhiteBalance"
return="void"
abstract="false"
@@ -72731,6 +73101,39 @@
visibility="public"
>
</field>
+<field name="AUTO_EXPOSURE_CENTER_WEIGHTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;meter-center&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTO_EXPOSURE_FRAME_AVG"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;meter-average&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTO_EXPOSURE_SPOT_METERING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;meter-spot&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EFFECT_AQUA"
type="java.lang.String"
transient="false"
@@ -72940,6 +73343,116 @@
visibility="public"
>
</field>
+<field name="FOCUS_MODE_NORMAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;normal&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ISO_100"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;100&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ISO_1250"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;1250&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ISO_200"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;200&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ISO_400"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;400&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ISO_800"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;800&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ISO_AUTO"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;auto&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ISO_HJR"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;deblur&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LENSSHADE_DISABLE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;disable&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LENSSHADE_ENABLE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;enable&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SCENE_MODE_ACTION"
type="java.lang.String"
transient="false"
@@ -73311,6 +73824,80 @@
>
</field>
</class>
+<class name="CameraSwitch"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="CameraSwitch"
+ type="android.hardware.CameraSwitch"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="hasCameraSwitch"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="openCamera"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cameraNode" type="java.lang.String">
+</parameter>
+</method>
+<method name="openMainCamera"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SWITCH_CAMERA_MAIN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;main&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SWITCH_CAMERA_SECONDARY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;secondary&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="GeomagneticField"
extends="java.lang.Object"
abstract="false"
@@ -82539,6 +83126,17 @@
<parameter name="quality" type="int">
</parameter>
</method>
+<field name="QUALITY_FRONT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="QUALITY_HIGH"
type="int"
transient="false"
@@ -82745,6 +83343,226 @@
>
</field>
</class>
+<class name="EncoderCapabilities"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getAudioEncoders"
+ return="java.util.List&lt;android.media.EncoderCapabilities.AudioEncoderCap&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOutputFileFormats"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVideoEncoders"
+ return="java.util.List&lt;android.media.EncoderCapabilities.VideoEncoderCap&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="EncoderCapabilities.AudioEncoderCap"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="mCodec"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMaxBitRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMaxChannels"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMaxSampleRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMinBitRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMinChannels"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMinSampleRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="EncoderCapabilities.VideoEncoderCap"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="mCodec"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMaxBitRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMaxFrameHeight"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMaxFrameRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMaxFrameWidth"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMinBitRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMinFrameHeight"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMinFrameRate"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mMinFrameWidth"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="ExifInterface"
extends="java.lang.Object"
abstract="false"
@@ -84544,6 +85362,21 @@
<parameter name="c" type="android.hardware.Camera">
</parameter>
</method>
+<method name="setCameraParameters"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="params" type="java.lang.String">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
<method name="setMaxDuration"
return="void"
abstract="false"
@@ -84825,6 +85658,17 @@
deprecated="not deprecated"
visibility="public"
>
+<field name="AAC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AMR_NB"
type="int"
transient="false"
@@ -169362,6 +170206,94 @@
visibility="public"
>
</field>
+<field name="KEYCODE_FUNC_1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="92"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_FUNC_2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="93"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_FUNC_3"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="94"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_FUNC_4"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="95"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_FUNC_5"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="96"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_FUNC_6"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="97"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_FUNC_7"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="98"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_FUNC_8"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="99"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KEYCODE_G"
type="int"
transient="false"
@@ -169692,6 +170624,17 @@
visibility="public"
>
</field>
+<field name="KEYCODE_QUECHAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="100"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KEYCODE_R"
type="int"
transient="false"
@@ -214021,7 +214964,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
diff --git a/awt/com/android/internal/awt/AndroidGraphics2D.java b/awt/com/android/internal/awt/AndroidGraphics2D.java
index 9a8ae02..b9cd091 100644
--- a/awt/com/android/internal/awt/AndroidGraphics2D.java
+++ b/awt/com/android/internal/awt/AndroidGraphics2D.java
@@ -406,7 +406,7 @@ public class AndroidGraphics2D extends Graphics2D {
mP.setStrokeWidth(0);
mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y,
- mP);
+ mP,false);
mP.setStyle(tmp);
}
@@ -1276,7 +1276,7 @@ public class AndroidGraphics2D extends Graphics2D {
@Override
public void drawChars(char[] data, int offset, int length, int x, int y) {
- mC.drawText(data, offset, length, x, y, mP);
+ mC.drawText(data, offset, length, x, y, mP,false);
}
@Override
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
index df5c166..4430541 100644
--- a/camera/libcameraservice/Android.mk
+++ b/camera/libcameraservice/Android.mk
@@ -48,9 +48,13 @@ LOCAL_SHARED_LIBRARIES:= \
libutils \
libbinder \
libcutils \
- libmedia \
- libcamera_client \
- libsurfaceflinger_client
+ libmedia
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client \
+ libcamera_client
+endif
LOCAL_MODULE:= libcameraservice
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 118249e..0ac089f 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -67,6 +67,16 @@ extern "C" {
static int debug_frame_cnt;
#endif
+struct camera_size_type {
+ int width;
+ int height;
+};
+
+static const camera_size_type preview_sizes[] = {
+ { 1280, 720 }, // 720P
+ { 768, 432 },
+};
+
static int getCallingPid() {
return IPCThreadState::self()->getCallingPid();
}
@@ -555,6 +565,13 @@ status_t CameraService::Client::setOverlay()
CameraParameters params(mHardware->getParameters());
params.getPreviewSize(&w, &h);
+ //for 720p recording , preview can be 800X448
+ if(w == preview_sizes[0].width && h==preview_sizes[0].height){
+ LOGD("Changing overlay dimensions to 768X432 for 720p recording.");
+ w = preview_sizes[1].width;
+ h = preview_sizes[1].height;
+ }
+
if ( w != mOverlayW || h != mOverlayH )
{
// Force the destruction of any previous overlay
@@ -606,6 +623,13 @@ status_t CameraService::Client::registerPreviewBuffers()
CameraParameters params(mHardware->getParameters());
params.getPreviewSize(&w, &h);
+ //for 720p recording , preview can be 800X448
+ if(w == preview_sizes[0].width && h== preview_sizes[0].height){
+ LOGD("registerpreviewbufs :changing dimensions to 768X432 for 720p recording.");
+ w = preview_sizes[1].width;
+ h = preview_sizes[1].height;
+ }
+
// don't use a hardcoded format here
ISurface::BufferHeap buffers(w, h, w, h,
HAL_PIXEL_FORMAT_YCrCb_420_SP,
@@ -886,32 +910,39 @@ status_t CameraService::Client::takePicture()
// snapshot taken
void CameraService::Client::handleShutter(
- image_rect_type *size // The width and height of yuv picture for
+ image_rect_type *size, // The width and height of yuv picture for
// registerBuffer. If this is NULL, use the picture
// size from parameters.
+ bool playShutterSoundOnly
)
{
// Play shutter sound.
- if (mMediaPlayerClick.get() != NULL) {
- // do not play shutter sound if stream volume is 0
- // (typically because ringer mode is silent).
- int index;
- AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index);
- if (index != 0) {
- mMediaPlayerClick->seekTo(0);
- mMediaPlayerClick->start();
+
+ if(playShutterSoundOnly) {
+
+ if (mMediaPlayerClick.get() != NULL) {
+ // do not play shutter sound if stream volume is 0
+ // (typically because ringer mode is silent).
+ int index;
+ AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index);
+ if (index != 0) {
+ mMediaPlayerClick->seekTo(0);
+ mMediaPlayerClick->start();
+ }
+ }
+ sp<ICameraClient> c = mCameraClient;
+ if (c != NULL) {
+ c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
}
+ return ;
}
+
// Screen goes black after the buffer is unregistered.
if (mSurface != 0 && !mUseOverlay) {
mSurface->unregisterBuffers();
}
- sp<ICameraClient> c = mCameraClient;
- if (c != NULL) {
- c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
- }
mHardware->disableMsgType(CAMERA_MSG_SHUTTER);
// It takes some time before yuvPicture callback to be called.
@@ -928,6 +959,7 @@ void CameraService::Client::handleShutter(
h &= ~1;
LOGV("Snapshot image width=%d, height=%d", w, h);
}
+
// FIXME: don't use hardcoded format constants here
ISurface::BufferHeap buffers(w, h, w, h,
HAL_PIXEL_FORMAT_YCrCb_420_SP, mOrientation, 0,
@@ -1085,7 +1117,7 @@ void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1, int32_
switch (msgType) {
case CAMERA_MSG_SHUTTER:
// ext1 is the dimension of the yuv picture.
- client->handleShutter((image_rect_type *)ext1);
+ client->handleShutter((image_rect_type *)ext1, (bool)ext2);
break;
default:
sp<ICameraClient> c = client->mCameraClient;
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index 75e96c6..f04f39c 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -144,7 +144,7 @@ private:
static sp<Client> getClientFromCookie(void* user);
void handlePreviewData(const sp<IMemory>&);
- void handleShutter(image_rect_type *image);
+ void handleShutter(image_rect_type *image, bool playShutterSoundOnly);
void handlePostview(const sp<IMemory>&);
void handleRawPicture(const sp<IMemory>&);
void handleCompressedPicture(const sp<IMemory>&);
diff --git a/camera/tests/CameraServiceTest/Android.mk b/camera/tests/CameraServiceTest/Android.mk
index 9bb190a..5bacb30 100644
--- a/camera/tests/CameraServiceTest/Android.mk
+++ b/camera/tests/CameraServiceTest/Android.mk
@@ -6,7 +6,7 @@ LOCAL_SRC_FILES:= CameraServiceTest.cpp
LOCAL_MODULE:= CameraServiceTest
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := eng tests
LOCAL_C_INCLUDES += \
frameworks/base/libs
@@ -17,8 +17,12 @@ LOCAL_SHARED_LIBRARIES += \
libbinder \
libcutils \
libutils \
- libui \
- libcamera_client \
- libsurfaceflinger_client
+ libui
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libcamera_client \
+ libsurfaceflinger_client
+endif
include $(BUILD_EXECUTABLE)
diff --git a/cmds/am/am b/cmds/am/am
index c823634..bc40e47 100755
--- a/cmds/am/am
+++ b/cmds/am/am
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/bmgr/bmgr b/cmds/bmgr/bmgr
index 6b4bbe2..60b5833 100755
--- a/cmds/bmgr/bmgr
+++ b/cmds/bmgr/bmgr
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "bmgr" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 2b89759..2876362 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -21,8 +21,12 @@ LOCAL_SHARED_LIBRARIES := \
libui \
libskia \
libEGL \
- libGLESv1_CM \
- libsurfaceflinger_client
+ libGLESv1_CM
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client
+endif
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
diff --git a/cmds/ime/ime b/cmds/ime/ime
index 96c56d3..1a1fdd9 100755
--- a/cmds/ime/ime
+++ b/cmds/ime/ime
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 41f070c..8d571dc 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -405,6 +405,7 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src)
char *tmp;
int srclen;
int dstlen;
+ char dexopt_data_only[PROPERTY_VALUE_MAX];
srclen = strlen(src);
@@ -417,7 +418,15 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src)
return -1;
}
- dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
+ const char *cache_path = DALVIK_CACHE_PREFIX;
+ if (!strncmp(src, "/system", 7)) {
+ property_get("dalvik.vm.dexopt-data-only", dexopt_data_only, "");
+ if (strcmp(dexopt_data_only, "1") != 0) {
+ cache_path = DALVIK_SYSTEM_CACHE_PREFIX;
+ }
+ }
+
+ dstlen = srclen + strlen(cache_path) +
strlen(DALVIK_CACHE_POSTFIX) + 1;
if (dstlen > PKG_PATH_MAX) {
@@ -425,11 +434,11 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src)
}
sprintf(path,"%s%s%s",
- DALVIK_CACHE_PREFIX,
+ cache_path,
src + 1, /* skip the leading / */
DALVIK_CACHE_POSTFIX);
- for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
+ for(tmp = path + strlen(cache_path); *tmp; tmp++) {
if (*tmp == '/') {
*tmp = '@';
}
@@ -454,6 +463,77 @@ static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
LOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
}
+static void run_check_zipalign(const char* input_file)
+{
+ static const char* ZIPALIGN_BIN = "/system/bin/zipalign";
+ execl(ZIPALIGN_BIN, ZIPALIGN_BIN, "-c", "4", input_file, (char*) NULL);
+}
+
+static void run_zipalign(const char* input_file, const char* output_file)
+{
+ static const char* ZIPALIGN_BIN = "/system/bin/zipalign";
+ execl(ZIPALIGN_BIN, ZIPALIGN_BIN, "4", input_file, output_file, (char*) NULL);
+ LOGE("execl(%s) failed: %s\n", ZIPALIGN_BIN, strerror(errno));
+}
+
+static int wait_check_zipalign(pid_t pid, const char* apk_path)
+{
+ int status;
+ pid_t got_pid;
+
+ while (1) {
+ got_pid = waitpid(pid, &status, 0);
+ if (got_pid == -1 && errno == EINTR) {
+ printf("waitpid interrupted, retrying\n");
+ } else {
+ break;
+ }
+ }
+
+ if (got_pid != pid) {
+ return 1;
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ LOGD("CheckZipAlign: --- END '%s' (not needed) ---\n", apk_path);
+ return 0;
+ } else {
+ LOGW("CheckZipAlign: --- END '%s' (needed) ---\n", apk_path);
+ return status;
+ }
+}
+
+static int wait_zipalign(pid_t pid, const char* apk_path)
+{
+ int status;
+ pid_t got_pid;
+
+ /*
+ * Wait for the zipalign process to finish.
+ */
+ while (1) {
+ got_pid = waitpid(pid, &status, 0);
+ if (got_pid == -1 && errno == EINTR) {
+ printf("waitpid interrupted, retrying\n");
+ } else {
+ break;
+ }
+ }
+ if (got_pid != pid) {
+ LOGW("waitpid failed: wanted %d, got %d: %s\n",
+ (int) pid, (int) got_pid, strerror(errno));
+ return 1;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ LOGD("ZipAlign: --- END '%s' (success) ---\n", apk_path);
+ return 0;
+ } else {
+ LOGW("ZipAlign: --- END '%s' --- status=0x%04x, process failed\n",
+ apk_path, status);
+ return status; /* always nonzero */
+ }
+}
+
static int wait_dexopt(pid_t pid, const char* apk_path)
{
int status;
@@ -486,6 +566,72 @@ static int wait_dexopt(pid_t pid, const char* apk_path)
}
}
+int zipalign(const char *apk_path, uid_t uid, int is_public)
+{
+ char za_path[PKG_PATH_MAX];
+ struct utimbuf ut;
+ struct stat za_stat, apk_stat;
+ int res;
+
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) {
+ run_check_zipalign(apk_path);
+ exit(67);
+ } else {
+ res = wait_check_zipalign(pid, apk_path);
+ if (res == 0) {
+ goto notneeded;
+ }
+ }
+
+ memset(&apk_stat, 0, sizeof(apk_stat));
+ stat(apk_path, &apk_stat);
+
+ strcpy(za_path, apk_path);
+ strcat(za_path, ".tmp");
+ LOGD("ZipAlign: --- BEGIN '%s' ---\n", apk_path);
+
+ pid = fork();
+ if (pid == 0) {
+ run_zipalign(apk_path, za_path);
+ exit(67);
+ } else {
+ res = wait_zipalign(pid, za_path);
+ if (res != 0) {
+ LOGE("zipalign failed on '%s' res = %d\n", za_path, res);
+ goto fail;
+ }
+ }
+
+ if (chown(za_path, apk_stat.st_uid, apk_stat.st_gid) < 0) {
+ LOGE("zipalign cannot chown '%s'", apk_path);
+ goto fail;
+ }
+ if (chmod(za_path, S_IRUSR|S_IWUSR|S_IRGRP |
+ (is_public ? S_IROTH : 0)) < 0) {
+ LOGE("zipalign cannot chmod '%s'\n", apk_path);
+ goto fail;
+ }
+
+ ut.actime = apk_stat.st_atime;
+ ut.modtime = apk_stat.st_mtime;
+ utime(za_path, &ut);
+
+ unlink(apk_path);
+ rename(za_path, apk_path);
+
+ return 0;
+
+notneeded:
+ return 0;
+
+fail:
+ unlink(za_path);
+ return -1;
+
+}
+
int dexopt(const char *apk_path, uid_t uid, int is_public)
{
struct utimbuf ut;
@@ -501,6 +647,10 @@ int dexopt(const char *apk_path, uid_t uid, int is_public)
if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
return -1;
}
+
+ if (strncmp(apk_path, "/system", 7) != 0) {
+ zipalign(apk_path, uid, is_public);
+ }
/* platform-specific flags affecting optimization and verification */
property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index cfcdb98..fc63b9f 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -64,6 +64,7 @@
#define SDCARD_DIR_PREFIX getenv("ASEC_MOUNTPOINT")
#define DALVIK_CACHE_PREFIX "/data/dalvik-cache/"
+#define DALVIK_SYSTEM_CACHE_PREFIX "/cache/dalvik-cache/"
#define DALVIK_CACHE_POSTFIX "/classes.dex"
#define UPDATE_COMMANDS_DIR_PREFIX "/system/etc/updatecmds/"
diff --git a/cmds/pm/pm b/cmds/pm/pm
index 8183838..53f85b2 100755
--- a/cmds/pm/pm
+++ b/cmds/pm/pm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/zipalign/Android.mk b/cmds/zipalign/Android.mk
new file mode 100644
index 0000000..3451b94
--- /dev/null
+++ b/cmds/zipalign/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 2008 The Android Open Source Project
+#
+# Zip alignment tool
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ ../../../../build/tools/zipalign/ZipFile.cpp \
+ ../../../../build/tools/zipalign/ZipEntry.cpp \
+ ../../../../build/tools/zipalign/ZipAlign.cpp
+
+LOCAL_C_INCLUDES := external/zlib build/tools/zipalign
+
+LOCAL_SHARED_LIBRARIES := \
+ libz \
+ libutils \
+ libcutils
+
+LOCAL_MODULE := zipalign
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index f0cef98..ec39ac7 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -174,7 +174,7 @@ public class ApplicationErrorReport implements Parcelable {
/**
* Return activity in receiverPackage that handles ACTION_APP_ERROR.
*
- * @param pm PackageManager isntance
+ * @param pm PackageManager instance
* @param errorPackage package which caused the error
* @param receiverPackage candidate package to receive the error
* @return activity component within receiverPackage which handles
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f471f57..0f9d314 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1690,8 +1690,9 @@ class ContextImpl extends Context {
if (resolveInfo == null) {
return null;
}
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setClassName(packageName, resolveInfo.activityInfo.name);
+ Intent intent = new Intent(intentToResolve);
+ intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName,
+ resolveInfo.activityInfo.name);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 6fe12fc..c2d61ab 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -16,12 +16,15 @@
package android.app;
+import java.io.FileOutputStream;
+
import android.content.Context;
import android.os.RemoteException;
import android.os.Handler;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
+import android.widget.Toast;
/**
* Class to notify the user of events that happen. This is how you tell
@@ -90,6 +93,22 @@ public class NotificationManager
notify(null, id, notification);
}
+ /** @hide */
+ public void updatePackageList() {
+ try {
+ if(mContext.getPackageName().equals("com.cyanogenmod.cmparts")) {
+ return;
+ }
+ //File file = new File(appContext.getFilesDir(), "trackball_lights");
+ FileOutputStream fos = mContext.openFileOutput("trackball_lights", Context.MODE_WORLD_READABLE);
+ String blank = "yes";
+ fos.write(blank.getBytes());
+ fos.close();
+ } catch(Exception e) {
+ Log.d("WriteApps", "Error: " + e.toString() );
+ }
+ }
+
/**
* Persistent notification on the status bar,
*
@@ -105,9 +124,13 @@ public class NotificationManager
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
+ if((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
+ updatePackageList();
+ }
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);
+ //Log.i("NotificationManager", "Pulsing: " + pkg);
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index c7fea9e..fc50ad0 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -201,6 +201,12 @@ public final class BluetoothClass implements Parcelable {
//public static final int AUDIO_VIDEO_RESERVED = 0x0444;
public static final int AUDIO_VIDEO_VIDEO_GAMING_TOY = 0x0448;
+ // Devices in the PERIPHERAL major class
+ public static final int PERIPHERAL_UNCATEGORIZED = 0x0500;
+ public static final int PERIPHERAL_KEYBORD = 0x0540;
+ public static final int PERIPHERAL_POINTING_DEVICE = 0x0580;
+ public static final int PERIPHERAL_COMBO_KEYBORD_POINTING = 0x05C0;
+
// Devices in the WEARABLE major class
public static final int WEARABLE_UNCATEGORIZED = 0x0700;
public static final int WEARABLE_WRIST_WATCH = 0x0704;
@@ -259,6 +265,8 @@ public final class BluetoothClass implements Parcelable {
public static final int PROFILE_A2DP = 1;
/** @hide */
public static final int PROFILE_OPP = 2;
+ /** @hide */
+ public static final int PROFILE_HID = 3;
/**
* Check class bits for possible bluetooth profile support.
diff --git a/core/java/android/bluetooth/BluetoothHid.java b/core/java/android/bluetooth/BluetoothHid.java
new file mode 100644
index 0000000..45347d3
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHid.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2009 ISB Corporation
+ * Copyright (C) 2010 0xlab
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.server.BluetoothHidService;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+/**
+ * Public API for controlling the Bluetooth HID Profile Service.
+ *
+ * BluetoothHid is a proxy object for controlling the Bluetooth HID
+ * Service via IPC.
+ *
+ *
+ * Currently the BluetoothHid service runs in the system server and this
+ * proxy object will be immediately bound to the service on construction.
+ * However this may change in future releases, and error codes such as
+ * BluetoothError.ERROR_IPC_NOT_READY will be returned from this API when the
+ * proxy object is not yet attached.
+ *
+ * Currently this class provides methods to connect to HID devices.
+ *
+ * @hide
+ */
+public class BluetoothHid {
+ private static final String TAG = "BluetoothHid";
+ private static final boolean DBG = false;
+
+ /** int extra for DEVICE_STATE_CHANGED_ACTION */
+ public static final String HID_DEVICE_STATE =
+ "android.bluetooth.hid.intent.HID_DEVICE_STATE";
+ /** int extra for DEVICE_STATE_CHANGED_ACTION */
+ public static final String HID_DEVICE_PREVIOUS_STATE =
+ "android.bluetooth.hid.intent.HID_DEVICE_PREVIOUS_STATE";
+
+ /** Indicates the state of an HID device has changed.
+ * This intent will always contain HID_DEVICE_STATE, and
+ * BluetoothIntent.ADDRESS extras.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String HID_DEVICE_STATE_CHANGED_ACTION =
+ "android.bluetooth.hid.intent.action.HID_DEVICE_STATE_CHANGED";
+
+ public static final int STATE_DISCONNECTED = 0;
+ public static final int STATE_CONNECTING = 1;
+ public static final int STATE_CONNECTED = 2;
+ public static final int STATE_DISCONNECTING = 3;
+
+ /** Default priority for hid devices that we try to auto-connect
+ * and allow incoming connections */
+ public static final int PRIORITY_AUTO_CONNECT = 1000;
+ /** Default priority for hid devices that should allow incoming
+ * connections */
+ public static final int PRIORITY_ON = 100;
+ /** Default priority for hid devices that should not allow incoming
+ * connections */
+ public static final int PRIORITY_OFF = 0;
+ /** Default priority when not set or when the device is unpaired */
+ public static final int PRIORITY_UNDEFINED = -1;
+
+ private final IBluetoothHid mService;
+ private final Context mContext;
+
+
+ /**
+ * Create a BluetoothHid proxy object.
+ */
+ public BluetoothHid(Context c) {
+ mContext = c;
+
+ IBinder b = ServiceManager.getService(BluetoothHidService.BLUETOOTH_HID_SERVICE);
+ if (b != null) {
+ mService = IBluetoothHid.Stub.asInterface(b);
+ } else {
+ Log.w(TAG, "Bluetooth HID service not available!");
+ // Instead of throwing an exception which prevents people from going
+ // into Wireless settings in the emulator. Let it crash later when it is actually used.
+ mService = null;
+ }
+ }
+
+
+ /** Initiate a connection to an HID device.
+ * Listen for HID_DEVICE_STATE_CHANGED_ACTION to find out when the
+ * connection is completed.
+ * @param address Remote BT address.
+ * @return Result code, negative indicates an immediate error.
+ * @hide
+ */
+ public boolean connectHidDevice(BluetoothDevice device) {
+ if (DBG) log("connectHidDevice(" + device + ")");
+ try {
+ return mService.connectHidDevice(device);
+ } catch (RemoteException e) {
+ Log.w(TAG, "", e);
+ return false;
+ }
+ }
+
+ /** Initiate disconnect from an HID device.
+ * Listen for HID_DEVICE_STATE_CHANGED_ACTION to find out when
+ * disconnect is completed.
+ * @param address Remote BT address.
+ * @return Result code, negative indicates an immediate error.
+ * @hide
+ */
+ public boolean disconnectHidDevice(BluetoothDevice device) {
+ try {
+ return mService.disconnectHidDevice(device);
+ } catch (RemoteException e) {
+ Log.w(TAG, "", e);
+ return false;
+ }
+ }
+
+ /** Check if a specified HID device is connected.
+ * @param address Remote BT address.
+ * @return True if connected (or playing), false otherwise and on error.
+ * @hide
+ */
+ public boolean isHidDeviceConnected(BluetoothDevice device) {
+ int state = getHidDeviceState(device);
+ return state == STATE_CONNECTED;
+ }
+
+ /** Check if any HID device is connected.
+ * @return a unmodifiable set of connected HID devices, or null on error.
+ * @hide
+ */
+ public Set<BluetoothDevice> getConnectedSinks() {
+ if (DBG) log("getConnectedSinks()");
+ try {
+ return Collections.unmodifiableSet(
+ new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks())));
+ } catch (RemoteException e) {
+ Log.w(TAG, "", e);
+ return null;
+ }
+ }
+
+ /** Check if any HID device is in Non Disconnected state
+ * i.e connected, connecting, disconnecting.
+ * @return a unmodifiable set of connected HID devices, or null on error.
+ * @hide
+ */
+ public Set<BluetoothDevice> getNonDisconnectedSinks() {
+ if (DBG) log("getNonDisconnectedSinks()");
+ try {
+ return Collections.unmodifiableSet(
+ new HashSet<BluetoothDevice>(Arrays.asList(mService.getNonDisconnectedSinks())));
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return null;
+ }
+ }
+
+ /** Get the state of an HID device
+ * @param address Remote BT address.
+ * @return State code, or negative on error
+ * @hide
+ */
+ public int getHidDeviceState(BluetoothDevice device) {
+ if (DBG) log("getHidDeviceState(" + device + ")");
+ try {
+ return mService.getHidDeviceState(device);
+ } catch (RemoteException e) {
+ Log.w(TAG, "", e);
+ return BluetoothHid.STATE_DISCONNECTED;
+ }
+ }
+
+
+ /**
+ * Set priority of HID device.
+ * Priority is a non-negative integer. By default paired devices will have
+ * a priority of PRIORITY_AUTO, and unpaired device PRIORITY_NONE (0).
+ * Sinks with priority greater than zero will accept incoming connections
+ * (if no sink is currently connected).
+ * Priority for unpaired sink must be PRIORITY_NONE.
+ * @param device Paired sink
+ * @param priority Integer priority, for example PRIORITY_AUTO or
+ * PRIORITY_NONE
+ * @return true if priority is set, false on error
+ */
+ public boolean setHidDevicePriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setHidDevicePriority(" + device + ", " + priority + ")");
+ try {
+ return mService.setHidDevicePriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return false;
+ }
+ }
+
+ /**
+ * Get priority of HID device.
+ * @param device Sink
+ * @return non-negative priority, or negative error code on error.
+ */
+ public int getHidDevicePriority(BluetoothDevice device) {
+ if (DBG) log("getHidDevicePriority(" + device + ")");
+ try {
+ return mService.getHidDevicePriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return PRIORITY_OFF;
+ }
+ }
+
+ /** Helper for converting a state to a string.
+ * For debug use only - strings are not internationalized.
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+
+ /**
+ * Check class bits for possible HID device support.
+ * This is a simple heuristic that tries to guess if a device with the
+ * given class bits might be a HID device. It is not accurate for all
+ * devices. It tries to err on the side of false positives.
+ * @return True if this device might be a HID device
+ */
+ public static boolean doesClassMatch(BluetoothClass btClass) {
+ switch (btClass.getDeviceClass()) {
+ case BluetoothClass.Device.PERIPHERAL_KEYBORD:
+ case BluetoothClass.Device.PERIPHERAL_POINTING_DEVICE:
+ case BluetoothClass.Device.PERIPHERAL_COMBO_KEYBORD_POINTING:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 4164a3d..f5f0ba6 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -49,10 +49,12 @@ public final class BluetoothUuid {
ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid ObexObjectPush =
ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
+ public static final ParcelUuid HID =
+ ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid[] RESERVED_UUIDS = {
AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
- ObexObjectPush};
+ ObexObjectPush,HID};
public static boolean isAudioSource(ParcelUuid uuid) {
return uuid.equals(AudioSource);
@@ -82,6 +84,10 @@ public final class BluetoothUuid {
return uuid.equals(AvrcpTarget);
}
+ public static boolean isHid(ParcelUuid uuid) {
+ return uuid.equals(HID);
+ }
+
/**
* Returns true if ParcelUuid is present in uuidArray
*
diff --git a/core/java/android/bluetooth/IBluetoothHid.aidl b/core/java/android/bluetooth/IBluetoothHid.aidl
new file mode 100644
index 0000000..5941083
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHid.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2009 ISB Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+import android.bluetooth.BluetoothDevice;
+/**
+ * System private API for Bluetooth HID service
+ *
+ * {@hide}
+ */
+interface IBluetoothHid {
+ boolean connectHidDevice(in BluetoothDevice device);
+ boolean disconnectHidDevice(in BluetoothDevice device);
+ BluetoothDevice[] getConnectedSinks(); // change to Set<> once AIDL supports
+ BluetoothDevice[] getNonDisconnectedSinks(); // change to Set<> once AIDL supports
+ int getHidDeviceState(in BluetoothDevice device);
+ boolean setHidDevicePriority(in BluetoothDevice device, int priority);
+ int getHidDevicePriority(in BluetoothDevice device);
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 0608cc0..44e589d 100644..100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -25,6 +25,7 @@ import org.xmlpull.v1.XmlPullParserException;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable.ConstantState;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemProperties;
@@ -41,6 +42,8 @@ import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.Locale;
+import android.graphics.PorterDuff.Mode;
+
/**
* Class for accessing an application's resources. This sits on top of the
* asset manager of the application (accessible through getAssets()) and
@@ -66,6 +69,8 @@ public class Resources {
= new LongSparseArray<Drawable.ConstantState>();
private static final SparseArray<ColorStateList> mPreloadedColorStateLists
= new SparseArray<ColorStateList>();
+ private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
+ = new LongSparseArray<Drawable.ConstantState>();
private static boolean mPreloaded;
/*package*/ final TypedValue mTmpValue = new TypedValue();
@@ -75,6 +80,8 @@ public class Resources {
= new LongSparseArray<WeakReference<Drawable.ConstantState> >();
private final SparseArray<WeakReference<ColorStateList> > mColorStateListCache
= new SparseArray<WeakReference<ColorStateList> >();
+ private final LongSparseArray<WeakReference<Drawable.ConstantState> > mColorDrawableCache
+ = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
private boolean mPreloading;
/*package*/ TypedArray mCachedStyledAttributes = null;
@@ -582,6 +589,41 @@ public class Resources {
}
}
+
+ /**
+ * Return a drawable object associated with a particular resource ID.
+ * Various types of objects will be returned depending on the underlying
+ * resource -- for example, a solid color, PNG image, scalable image, etc.
+ * The Drawable API hides these implementation details.
+ *
+ * mtwebster:
+ * This version also applies a Porter Duff color mask onto the object before
+ * returning the object. Put in Resources to give reusability, I plan on
+ * applying this to other parts of the gui
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ *
+ * @param mask The color mask to use (alpha-r-g-b)
+ *
+ * @param masktype The Porter Duff filter mode
+ *
+ * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+ *
+ * @return Drawable An object that can be used to draw this resource.
+ * @hide
+ */
+ public Drawable getDrawable(int id, int mask, Mode maskType) throws NotFoundException {
+ synchronized (mTmpValue) {
+ TypedValue value = mTmpValue;
+ getValue(id, value, true);
+ Drawable tmpDrawable = loadDrawable(value, id);
+ tmpDrawable.setColorFilter(mask, maskType);
+ return tmpDrawable;
+ }
+ }
+
/**
* Return a movie object associated with the particular resource ID.
* @param id The desired resource identifier, as generated by the aapt
@@ -1299,37 +1341,13 @@ public class Resources {
(int)(mMetrics.density*160), mConfiguration.keyboard,
keyboardHidden, mConfiguration.navigation, width, height,
mConfiguration.screenLayout, mConfiguration.uiMode, sSdkVersion);
- int N = mDrawableCache.size();
- if (DEBUG_CONFIG) {
- Log.d(TAG, "Cleaning up drawables config changes: 0x"
- + Integer.toHexString(configChanges));
- }
- for (int i=0; i<N; i++) {
- WeakReference<Drawable.ConstantState> ref = mDrawableCache.valueAt(i);
- if (ref != null) {
- Drawable.ConstantState cs = ref.get();
- if (cs != null) {
- if (Configuration.needNewResources(
- configChanges, cs.getChangingConfigurations())) {
- if (DEBUG_CONFIG) {
- Log.d(TAG, "FLUSHING #0x"
- + Long.toHexString(mDrawableCache.keyAt(i))
- + " / " + cs + " with changes: 0x"
- + Integer.toHexString(cs.getChangingConfigurations()));
- }
- mDrawableCache.setValueAt(i, null);
- } else if (DEBUG_CONFIG) {
- Log.d(TAG, "(Keeping #0x"
- + Long.toHexString(mDrawableCache.keyAt(i))
- + " / " + cs + " with changes: 0x"
- + Integer.toHexString(cs.getChangingConfigurations())
- + ")");
- }
- }
- }
- }
- mDrawableCache.clear();
+
+ clearDrawableCache(mDrawableCache, configChanges);
+ clearDrawableCache(mColorDrawableCache, configChanges);
+
mColorStateListCache.clear();
+
+
flushLayoutCache();
}
synchronized (mSync) {
@@ -1339,6 +1357,41 @@ public class Resources {
}
}
+ private void clearDrawableCache(
+ LongSparseArray<WeakReference<ConstantState>> cache,
+ int configChanges) {
+ int N = cache.size();
+ if (DEBUG_CONFIG) {
+ Log.d(TAG, "Cleaning up drawables config changes: 0x"
+ + Integer.toHexString(configChanges));
+ }
+ for (int i=0; i<N; i++) {
+ WeakReference<Drawable.ConstantState> ref = cache.valueAt(i);
+ if (ref != null) {
+ Drawable.ConstantState cs = ref.get();
+ if (cs != null) {
+ if (Configuration.needNewResources(
+ configChanges, cs.getChangingConfigurations())) {
+ if (DEBUG_CONFIG) {
+ Log.d(TAG, "FLUSHING #0x"
+ + Long.toHexString(mDrawableCache.keyAt(i))
+ + " / " + cs + " with changes: 0x"
+ + Integer.toHexString(cs.getChangingConfigurations()));
+ }
+ cache.setValueAt(i, null);
+ } else if (DEBUG_CONFIG) {
+ Log.d(TAG, "(Keeping #0x"
+ + Long.toHexString(cache.keyAt(i))
+ + " / " + cs + " with changes: 0x"
+ + Integer.toHexString(cs.getChangingConfigurations())
+ + ")");
+ }
+ }
+ }
+ }
+ cache.clear();
+ }
+
/**
* Update the system resources configuration if they have previously
* been initialized.
@@ -1661,13 +1714,18 @@ public class Resources {
}
final long key = (((long) value.assetCookie) << 32) | value.data;
- Drawable dr = getCachedDrawable(key);
+ boolean isColorDrawable = false;
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
+ value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ isColorDrawable = true;
+ }
+ Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);
if (dr != null) {
return dr;
}
- Drawable.ConstantState cs = sPreloadedDrawables.get(key);
+ Drawable.ConstantState cs = isColorDrawable ? sPreloadedColorDrawables.get(key) : sPreloadedDrawables.get(key);
if (cs != null) {
dr = cs.newDrawable(this);
} else {
@@ -1726,13 +1784,21 @@ public class Resources {
cs = dr.getConstantState();
if (cs != null) {
if (mPreloading) {
- sPreloadedDrawables.put(key, cs);
+ if (isColorDrawable) {
+ sPreloadedColorDrawables.put(key, cs);
+ } else {
+ sPreloadedDrawables.put(key, cs);
+ }
} else {
synchronized (mTmpValue) {
//Log.i(TAG, "Saving cached drawable @ #" +
// Integer.toHexString(key.intValue())
// + " in " + this + ": " + cs);
- mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
+ if (isColorDrawable) {
+ mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
+ } else {
+ mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
+ }
}
}
}
@@ -1741,9 +1807,11 @@ public class Resources {
return dr;
}
- private Drawable getCachedDrawable(long key) {
+ private Drawable getCachedDrawable(
+ LongSparseArray<WeakReference<ConstantState>> drawableCache,
+ long key) {
synchronized (mTmpValue) {
- WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key);
+ WeakReference<Drawable.ConstantState> wr = drawableCache.get(key);
if (wr != null) { // we have the key
Drawable.ConstantState entry = wr.get();
if (entry != null) {
@@ -1753,7 +1821,7 @@ public class Resources {
return entry.newDrawable(this);
}
else { // our entry has been purged
- mDrawableCache.delete(key);
+ drawableCache.delete(key);
}
}
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 59c386d..014e21d 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -162,9 +162,18 @@ public class Camera {
* example, if the camera is in use by another process).
*/
public static Camera open() {
+ CameraSwitch.openMainCamera();
return new Camera();
}
+ /**
+ * Returns a new Camera object for the given cameraNode
+ */
+ public static Camera open(String cameraNode) {
+ CameraSwitch.openCamera(cameraNode);
+ return new Camera();
+ }
+
Camera() {
mShutterCallback = null;
mRawImageCallback = null;
@@ -804,7 +813,11 @@ public class Camera {
* @see #getParameters()
*/
public void setParameters(Parameters params) {
- native_setParameters(params.flatten());
+ try {
+ native_setParameters(params.flatten());
+ } catch (RuntimeException ex) {
+ Log.e(TAG, "Failed to set all parameters");
+ }
}
/**
@@ -901,6 +914,8 @@ public class Camera {
private static final String KEY_SCENE_MODE = "scene-mode";
private static final String KEY_FLASH_MODE = "flash-mode";
private static final String KEY_FOCUS_MODE = "focus-mode";
+ private static final String KEY_ISO_MODE = "iso";
+ private static final String KEY_LENSSHADE = "lensshade";
private static final String KEY_FOCAL_LENGTH = "focal-length";
private static final String KEY_HORIZONTAL_VIEW_ANGLE = "horizontal-view-angle";
private static final String KEY_VERTICAL_VIEW_ANGLE = "vertical-view-angle";
@@ -908,11 +923,26 @@ public class Camera {
private static final String KEY_MAX_EXPOSURE_COMPENSATION = "max-exposure-compensation";
private static final String KEY_MIN_EXPOSURE_COMPENSATION = "min-exposure-compensation";
private static final String KEY_EXPOSURE_COMPENSATION_STEP = "exposure-compensation-step";
+ private static final String KEY_AUTO_EXPOSURE = "meter-mode";
private static final String KEY_ZOOM = "zoom";
private static final String KEY_MAX_ZOOM = "max-zoom";
private static final String KEY_ZOOM_RATIOS = "zoom-ratios";
private static final String KEY_ZOOM_SUPPORTED = "zoom-supported";
private static final String KEY_SMOOTH_ZOOM_SUPPORTED = "smooth-zoom-supported";
+ private static final String KEY_SHARPNESS = "sharpness";
+ private static final String KEY_MAX_SHARPNESS = "sharpness-max";
+ private static final String KEY_DEFAULT_SHARPNESS = "sharpness-def";
+ private static final String KEY_CONTRAST = "contrast";
+ private static final String KEY_MAX_CONTRAST = "contrast-max";
+ private static final String KEY_DEFAULT_CONTRAST = "contrast-def";
+ private static final String KEY_SATURATION = "saturation";
+ private static final String KEY_MAX_SATURATION = "saturation-max";
+ private static final String KEY_DEFAULT_SATURATION = "saturation-def";
+ private static final String KEY_BRIGHTNESS = "brightness";
+ private static final String KEY_MAX_BRIGHTNESS = "brightness-max";
+ private static final String KEY_DEFAULT_BRIGHTNESS = "brightness-def";
+ private static final String KEY_SMART_CONTRAST = "smart-contrast";
+
// Parameter key suffix for supported values.
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -939,12 +969,34 @@ public class Camera {
public static final String EFFECT_BLACKBOARD = "blackboard";
public static final String EFFECT_AQUA = "aqua";
+ // Values for auto exposure settings.
+ public static final String AUTO_EXPOSURE_FRAME_AVG = "meter-average";
+ public static final String AUTO_EXPOSURE_CENTER_WEIGHTED = "meter-center";
+ public static final String AUTO_EXPOSURE_SPOT_METERING = "meter-spot";
+
// Values for antibanding settings.
public static final String ANTIBANDING_AUTO = "auto";
public static final String ANTIBANDING_50HZ = "50hz";
public static final String ANTIBANDING_60HZ = "60hz";
public static final String ANTIBANDING_OFF = "off";
+ //Values for ISO settings
+
+ public static final String ISO_AUTO = "auto";
+ public static final String ISO_HJR = "deblur";
+ public static final String ISO_100 = "100";
+ public static final String ISO_200 = "200";
+ public static final String ISO_400 = "400";
+ public static final String ISO_800 = "800";
+ public static final String ISO_1250 = "1250";
+
+ //Values for Lens Shading
+
+ public static final String LENSSHADE_ENABLE = "enable";
+ public static final String LENSSHADE_DISABLE= "disable";
+
+
+
// Values for flash mode settings.
/**
* Flash will not be fired.
@@ -1008,6 +1060,7 @@ public class Camera {
* {@link #autoFocus(AutoFocusCallback)} in this mode.
*/
public static final String FOCUS_MODE_INFINITY = "infinity";
+ public static final String FOCUS_MODE_NORMAL = "normal";
public static final String FOCUS_MODE_MACRO = "macro";
/**
@@ -1145,7 +1198,8 @@ public class Camera {
* @return the int value of the parameter
*/
public int getInt(String key) {
- return Integer.parseInt(mMap.get(key));
+ String value = mMap.get(key);
+ return value == null ? 0 : Integer.parseInt(value);
}
/**
@@ -1330,6 +1384,9 @@ public class Camera {
*/
public List<Integer> getSupportedPreviewFormats() {
String str = get(KEY_PREVIEW_FORMAT + SUPPORTED_VALUES_SUFFIX);
+ if (str == null) {
+ str = get(KEY_PREVIEW_FORMAT);
+ }
ArrayList<Integer> formats = new ArrayList<Integer>();
for (String s : split(str)) {
int f = pixelFormatForCameraFormat(s);
@@ -1626,6 +1683,166 @@ public class Camera {
/**
+ * Get Sharpness level
+ *
+ * @return sharpness level
+ */
+ public float getSharpness(){
+ return getFloat(KEY_SHARPNESS, 0.0f);
+ }
+
+ /**
+ * Set Sharpness Level
+ *
+ * @param sharpness level
+ */
+ public void setSharpness(float sharpness){
+ if((sharpness < 0) || (sharpness > getMaxSharpness()) )
+ throw new IllegalArgumentException(
+ "Invalid Sharpness " + sharpness);
+
+ set(KEY_SHARPNESS, String.valueOf(sharpness));
+ }
+
+ /**
+ * Get Max Sharpness Level
+ *
+ * @return max sharpness level
+ */
+ public float getMaxSharpness(){
+ return getFloat(KEY_MAX_SHARPNESS, 0.0f);
+ }
+
+ /**
+ * Get default sharpness level
+ *
+ * @return default sharpness level
+ */
+ public float getDefaultSharpness() {
+ return getFloat(KEY_DEFAULT_SHARPNESS, 0.0f);
+ }
+
+ /**
+ * Get Contrast level
+ *
+ * @return contrast level
+ */
+ public float getContrast(){
+ return getFloat(KEY_CONTRAST, 0.0f);
+ }
+
+ /**
+ * Set Contrast Level
+ *
+ * @param contrast level
+ */
+ public void setContrast(float contrast){
+ if((contrast < 0 ) || (contrast > getMaxContrast()))
+ throw new IllegalArgumentException(
+ "Invalid Contrast " + contrast);
+
+ set(KEY_CONTRAST, String.valueOf(contrast));
+ }
+
+ /**
+ * Get Max Contrast Level
+ *
+ * @return max contrast level
+ */
+ public float getMaxContrast(){
+ return getFloat(KEY_MAX_CONTRAST, 0.0f);
+ }
+
+ /**
+ * Get default contrast level
+ *
+ * @return default contrast level
+ */
+ public float getDefaultContrast() {
+ return getFloat(KEY_DEFAULT_CONTRAST, 0.0f);
+ }
+
+ /**
+ * Get Saturation level
+ *
+ * @return saturation level
+ */
+ public float getSaturation(){
+ return getFloat(KEY_SATURATION, 0.0f);
+ }
+
+ /**
+ * Set Saturation Level
+ *
+ * @param saturation level
+ */
+ public void setSaturation(float saturation){
+ if((saturation < 0 ) || (saturation > getMaxSaturation()))
+ throw new IllegalArgumentException(
+ "Invalid Saturation " + saturation);
+
+ set(KEY_SATURATION, String.valueOf(saturation));
+ }
+
+ /**
+ * Get Max Saturation Level
+ *
+ * @return max contrast level
+ */
+ public float getMaxSaturation(){
+ return getFloat(KEY_MAX_SATURATION, 0.0f);
+ }
+
+ /**
+ * Get default saturation level
+ *
+ * @return default saturation level
+ */
+ public float getDefaultSaturation() {
+ return getFloat(KEY_DEFAULT_SATURATION, 0.0f);
+ }
+
+ /**
+ * Get brightness level
+ *
+ * @return brightness level
+ */
+ public float getBrightness(){
+ return getFloat(KEY_BRIGHTNESS, 0.0f);
+ }
+
+ /**
+ * Set brightness level
+ *
+ * @param brightness level
+ */
+ public void setBrightness(float brightness){
+ if((brightness < 0 ) || (brightness > getMaxBrightness()))
+ throw new IllegalArgumentException(
+ "Invalid Brightness " + brightness);
+
+ set(KEY_BRIGHTNESS, String.valueOf(brightness));
+ }
+
+ /**
+ * Get Max Brightness Level
+ *
+ * @return max brightness level
+ */
+ public float getMaxBrightness(){
+ return getFloat(KEY_MAX_BRIGHTNESS, 0.0f);
+ }
+
+ /**
+ * Get default brightness level
+ *
+ * @return default brightness level
+ */
+ public float getDefaultBrightness() {
+ return getFloat(KEY_DEFAULT_BRIGHTNESS, 0.0f);
+ }
+
+ /**
* Gets the current antibanding setting.
*
* @return current antibanding. null if antibanding setting is not
@@ -1903,7 +2120,11 @@ public class Camera {
* @param value zoom value. The valid range is 0 to {@link #getMaxZoom}.
*/
public void setZoom(int value) {
- set(KEY_ZOOM, value);
+ if (mMap.containsKey("taking-picture-zoom")) {
+ set("taking-picture-zoom", value);
+ } else {
+ set(KEY_ZOOM, value);
+ }
}
/**
@@ -1914,7 +2135,7 @@ public class Camera {
*/
public boolean isZoomSupported() {
String str = get(KEY_ZOOM_SUPPORTED);
- return TRUE.equals(str);
+ return TRUE.equals(str) && getMaxZoom() > 0;
}
/**
@@ -1927,7 +2148,11 @@ public class Camera {
* @return the maximum zoom value supported by the camera.
*/
public int getMaxZoom() {
- return getInt(KEY_MAX_ZOOM, 0);
+ if (mMap.containsKey("taking-picture-zoom-max")) {
+ return getInt("taking-picture-zoom-max", 0);
+ } else {
+ return getInt(KEY_MAX_ZOOM, 0);
+ }
}
/**
@@ -1955,6 +2180,112 @@ public class Camera {
return TRUE.equals(str);
}
+ /**
+ * Gets the current ISO setting.
+ *
+ * @return one of ISO_XXX string constant. null if ISO
+ * setting is not supported.
+ */
+ public String getISOValue() {
+ return get(KEY_ISO_MODE);
+ }
+
+ /**
+ * Sets the ISO.
+ *
+ * @param iso ISO_XXX string constant.
+ */
+ public void setISOValue(String iso) {
+ set(KEY_ISO_MODE, iso);
+ }
+
+ /**
+ * Gets the supported ISO values.
+ *
+ * @return a List of FLASH_MODE_XXX string constants. null if flash mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedIsoValues() {
+ String str = get(KEY_ISO_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /**
+ * Gets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public String getLensShade() {
+ return get(KEY_LENSSHADE);
+ }
+
+ /**
+ * Sets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public void setLensShade(String lensshade) {
+ set(KEY_LENSSHADE, lensshade);
+ }
+
+ /**
+ * Gets the supported Lensshade modes.
+ *
+ * @return a List of LENS_MODE_XXX string constants. null if lens mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedLensShadeModes() {
+ String str = get(KEY_LENSSHADE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /**
+ * Gets the current auto exposure setting.
+ *
+ * @return one of AUTO_EXPOSURE_XXX string constant. null if auto exposure
+ * setting is not supported.
+ */
+ public String getAutoExposure() {
+ return get(KEY_AUTO_EXPOSURE);
+ }
+
+ /**
+ * Sets the current auto exposure setting.
+ *
+ * @param value AUTO_EXPOSURE_XXX string constants.
+ */
+ public void setAutoExposure(String value) {
+ set(KEY_AUTO_EXPOSURE, value);
+ }
+
+ /**
+ * Gets the supported auto exposure setting.
+ *
+ * @return a List of AUTO_EXPOSURE_XXX string constants. null if auto exposure
+ * setting is not supported.
+ */
+ public List<String> getSupportedAutoexposure() {
+ String str = get(KEY_AUTO_EXPOSURE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /**
+ * Sets the smart-contrast feature
+ * @param boolean
+ */
+ public void setSmartContrastEnabled(boolean enabled) {
+ set(KEY_SMART_CONTRAST, enabled ? "on" : "off");
+ }
+
+ /**
+ * Gets the value of smart-contrast
+ *
+ * @return if smart-contrast is enabled
+ */
+ public boolean isSmartContrastEnabled() {
+ return "on".equals(get(KEY_SMART_CONTRAST));
+ }
+
// Splits a comma delimited string to an ArrayList of String.
// Return null if the passing string is null or the size is 0.
private ArrayList<String> split(String str) {
@@ -1986,6 +2317,9 @@ public class Camera {
// Returns the value of a float parameter.
private float getFloat(String key, float defaultValue) {
+ if (!mMap.containsKey(key)) {
+ return defaultValue;
+ }
try {
return Float.parseFloat(mMap.get(key));
} catch (NumberFormatException ex) {
@@ -1995,6 +2329,9 @@ public class Camera {
// Returns the value of a integer parameter.
private int getInt(String key, int defaultValue) {
+ if (!mMap.containsKey(key)) {
+ return defaultValue;
+ }
try {
return Integer.parseInt(mMap.get(key));
} catch (NumberFormatException ex) {
diff --git a/core/java/android/hardware/CameraSwitch.java b/core/java/android/hardware/CameraSwitch.java
new file mode 100644
index 0000000..2475630
--- /dev/null
+++ b/core/java/android/hardware/CameraSwitch.java
@@ -0,0 +1,80 @@
+package android.hardware;
+
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * Handle switching for HTC devices with dual cameras.
+ */
+public class CameraSwitch {
+
+ public static final String SWITCH_CAMERA_MAIN = "main";
+
+ public static final String SWITCH_CAMERA_SECONDARY = "secondary";
+
+ private static final String SWITCH_CAMERA_FILE_PATH = "/sys/android_camera2/htcwc";
+
+ private static final String LOG_TAG = "CameraSwitch";
+
+ private static final boolean HAS_CAMERA_SWITCH;
+
+ static {
+ final File file = new File(SWITCH_CAMERA_FILE_PATH);
+ HAS_CAMERA_SWITCH = file.exists();
+ }
+
+ private static boolean setHTCCameraSwitch(String cameraSwitch) {
+ if (!HAS_CAMERA_SWITCH) {
+ return false;
+ }
+
+ final String node;
+ if (SWITCH_CAMERA_MAIN.equals(cameraSwitch)) {
+ node = "0";
+ Log.d(LOG_TAG, "Open main camera");
+ } else if (SWITCH_CAMERA_SECONDARY.equals(cameraSwitch)) {
+ node = "1";
+ Log.d(LOG_TAG, "Open secondary camera");
+ } else {
+ Log.e(LOG_TAG, "Unknown camera node: " + cameraSwitch + ", using main");
+ node = "0";
+ }
+
+ final File file = new File(SWITCH_CAMERA_FILE_PATH);
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(file));
+ writer.write(node);
+ writer.flush();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Can't open " + SWITCH_CAMERA_FILE_PATH, e);
+ return false;
+ } finally {
+ try {
+ if (writer != null) {
+ writer.close();
+ }
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Error closing " + SWITCH_CAMERA_FILE_PATH, e);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void openCamera(String cameraNode) {
+ setHTCCameraSwitch(cameraNode);
+ }
+
+ public static void openMainCamera() {
+ setHTCCameraSwitch(SWITCH_CAMERA_MAIN);
+ }
+
+ public static boolean hasCameraSwitch() {
+ return HAS_CAMERA_SWITCH;
+ }
+}
diff --git a/core/java/android/hardware/HtcFrontFacingCamera.java b/core/java/android/hardware/HtcFrontFacingCamera.java
new file mode 100644
index 0000000..5846579
--- /dev/null
+++ b/core/java/android/hardware/HtcFrontFacingCamera.java
@@ -0,0 +1,14 @@
+package android.hardware;
+
+/**
+ * For compatibility with apps written for the EVO 4G.
+ *
+ * @hide
+ */
+public class HtcFrontFacingCamera extends Camera {
+
+ public static Camera getCamera() {
+ return open(CameraSwitch.SWITCH_CAMERA_SECONDARY);
+ }
+
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 280ded6..daf86c8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -200,7 +200,8 @@ public class ConnectivityManager
private IConnectivityManager mService;
static public boolean isNetworkTypeValid(int networkType) {
- return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
+ // HACK! Accept TYPE_WIMAX even though we don't support it yet
+ return TYPE_WIMAX == networkType || (networkType >= 0 && networkType <= MAX_NETWORK_TYPE);
}
public void setNetworkPreference(int preference) {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 649cb8c..cfb4b30 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -373,4 +373,13 @@ public class NetworkInfo implements Parcelable {
return new NetworkInfo[size];
}
};
+
+ /**
+ * HACK! Get an empty NetworkInfo object for WIMAX stub
+ * @hide
+ */
+ public static final NetworkInfo getEmptyWimaxNetworkInfo() {
+ return new NetworkInfo(ConnectivityManager.TYPE_WIMAX, 0, "", "");
+ }
+
}
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 66eefb2..39d4ac1 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -16,12 +16,20 @@
package android.net;
+import org.apache.harmony.luni.platform.INetworkSystem;
+import org.apache.harmony.luni.platform.Platform;
+import org.apache.http.HttpHost;
+
import android.content.ContentResolver;
import android.content.Context;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.UnknownHostException;
+
import junit.framework.Assert;
/**
@@ -36,6 +44,8 @@ final public class Proxy {
static final public String PROXY_CHANGE_ACTION =
"android.intent.action.PROXY_CHANGE";
+ static final private INetworkSystem NETIMPL = Platform.getNetworkSystem();
+
/**
* Return the proxy host set by the user.
* @param ctx A Context used to get the settings for the proxy host.
@@ -120,4 +130,74 @@ final public class Proxy {
}
}
+ /**
+ * Returns the preferred proxy to be used by clients. This is a wrapper
+ * around {@link android.net.Proxy#getHost()}. Currently no proxy will
+ * be returned for localhost or if the active network is Wi-Fi.
+ *
+ * @param context the context which will be passed to
+ * {@link android.net.Proxy#getHost()}
+ * @param url the target URL for the request
+ * @note Calling this method requires permission
+ * android.permission.ACCESS_NETWORK_STATE
+ * @return The preferred proxy to be used by clients, or null if there
+ * is no proxy.
+ *
+ * {@hide}
+ */
+ static final public HttpHost getPreferredHttpHost(Context context,
+ String url) {
+ if (!isLocalHost(url) && !isNetworkWifi(context)) {
+ final String proxyHost = Proxy.getHost(context);
+ if (proxyHost != null) {
+ return new HttpHost(proxyHost, Proxy.getPort(context), "http");
+ }
+ }
+
+ return null;
+ }
+
+ static final private boolean isLocalHost(String url) {
+ if (url == null) {
+ return false;
+ }
+
+ try {
+ final URI uri = URI.create(url);
+ final String host = uri.getHost();
+ if (host != null) {
+ if (host.equalsIgnoreCase("localhost")) {
+ return true;
+ }
+ if (InetAddress.getByAddress(NETIMPL.ipStringToByteArray(host))
+ .isLoopbackAddress()) {
+ return true;
+ }
+ }
+ } catch (UnknownHostException uex) {
+ // Ignore (INetworkSystem.ipStringToByteArray)
+ } catch (IllegalArgumentException iex) {
+ // Ignore (URI.create)
+ }
+
+ return false;
+ }
+
+ static final private boolean isNetworkWifi(Context context) {
+ if (context == null) {
+ return false;
+ }
+
+ final ConnectivityManager connectivity = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connectivity != null) {
+ final NetworkInfo info = connectivity.getActiveNetworkInfo();
+ if (info != null &&
+ info.getType() == ConnectivityManager.TYPE_WIFI) {
+ return true;
+ }
+ }
+
+ return false;
+ }
};
diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java
index 43fb5f1..5e5affc 100644
--- a/core/java/android/net/http/Connection.java
+++ b/core/java/android/net/http/Connection.java
@@ -47,11 +47,16 @@ abstract class Connection {
*/
static final int SOCKET_TIMEOUT = 60000;
+ private static final int MAX_PRIORITY = 1000;
+
private static final int SEND = 0;
private static final int READ = 1;
private static final int DRAIN = 2;
private static final int DONE = 3;
- private static final String[] states = {"SEND", "READ", "DRAIN", "DONE"};
+ private static final int PRIO = 4;
+ private static final String[] states = {"SEND", "READ", "DRAIN", "DONE", "PRIO"};
+
+ private ConnectionThread mConnectionThread;
Context mContext;
@@ -110,6 +115,7 @@ abstract class Connection {
mCanPersist = false;
mHttpContext = new BasicHttpContext(null);
+ mConnectionThread = null;
}
HttpHost getHost() {
@@ -140,6 +146,10 @@ abstract class Connection {
return mCertificate;
}
+ void setConnectionThread(ConnectionThread thread) {
+ mConnectionThread = thread;
+ }
+
/**
* Close current network connection
* Note: this runs in non-network thread
@@ -157,6 +167,7 @@ abstract class Connection {
*/
void processRequests(Request firstRequest) {
Request req = null;
+ Request peek = null;
boolean empty;
int error = EventHandler.OK;
Exception exception = null;
@@ -197,6 +208,36 @@ abstract class Connection {
state = DRAIN;
break;
}
+
+ // ### synchronize on mRequestFeeder instead of requeing newreq?
+
+ if (req.mPriority == -1 ||
+ req.mPriority > MAX_PRIORITY) {
+ /*
+ || pipe.size() + 1 == maxPipe
+ || req.mPriority == -1) {
+ */
+ peek = mRequestFeeder.peekRequest();
+ if (peek != null) {
+ int ppri = peek.mPriority;
+ if ((req.mPriority == -1 && ppri >= 0)
+ || (req.mPriority >= 0 && ppri < req.mPriority)) {
+ Request newreq = mRequestFeeder.getRequest();
+ if (newreq != null) {
+ if (!newreq.equals(peek)
+ || peek.mPriority != ppri) {
+ mRequestFeeder.requeueRequest(newreq, false, true);
+ } else {
+ mConnectionThread.setNewRequest(newreq);
+ state = PRIO;
+ mRequestFeeder.requeueRequest(req, false, true);
+ break;
+ }
+ }
+ }
+ }
+ }
+
req.setConnection(this);
/* Don't work on cancelled requests. */
@@ -251,27 +292,34 @@ abstract class Connection {
pipe.addLast(req);
}
exception = null;
- state = clearPipe(pipe) ? DONE : SEND;
+ if (clearPipe(pipe))
+ state = DONE;
+ else if (state != PRIO)
+ state = SEND;
minPipe = maxPipe = 1;
break;
}
pipe.addLast(req);
- if (!mCanPersist) state = READ;
+ if (!mCanPersist && state != PRIO) state = READ;
break;
}
+ case PRIO:
case DRAIN:
case READ: {
empty = !mRequestFeeder.haveRequest(mHost);
int pipeSize = pipe.size();
- if (state != DRAIN && pipeSize < minPipe &&
+ if (state != PRIO && state != DRAIN && pipeSize < minPipe &&
!empty && mCanPersist) {
state = SEND;
break;
} else if (pipeSize == 0) {
/* Done if no other work to do */
- state = empty ? DONE : SEND;
+ if (state == PRIO)
+ state = DONE;
+ else
+ state = empty ? DONE : SEND;
break;
}
@@ -312,7 +360,8 @@ abstract class Connection {
mHttpContext.removeAttribute(HTTP_CONNECTION);
clearPipe(pipe);
minPipe = maxPipe = 1;
- state = SEND;
+ if (state != PRIO)
+ state = SEND;
}
break;
}
@@ -335,7 +384,7 @@ abstract class Connection {
tReq = (Request)pipe.removeLast();
if (HttpLog.LOGV) HttpLog.v(
"clearPipe() adding back " + mHost + " " + tReq);
- mRequestFeeder.requeueRequest(tReq);
+ mRequestFeeder.requeueRequest(tReq, true, false);
empty = false;
}
if (empty) empty = !mRequestFeeder.haveRequest(mHost);
@@ -406,7 +455,7 @@ abstract class Connection {
} else {
if (req.mFailCount < RETRY_REQUEST_LIMIT) {
// requeue
- mRequestFeeder.requeueRequest(req);
+ mRequestFeeder.requeueRequest(req, true, false);
req.mFailCount++;
} else {
httpFailure(req, error, exception);
diff --git a/core/java/android/net/http/ConnectionThread.java b/core/java/android/net/http/ConnectionThread.java
index 32191d2..9b0363e 100644
--- a/core/java/android/net/http/ConnectionThread.java
+++ b/core/java/android/net/http/ConnectionThread.java
@@ -40,6 +40,8 @@ class ConnectionThread extends Thread {
private Context mContext;
private RequestQueue.ConnectionManager mConnectionManager;
private RequestFeeder mRequestFeeder;
+ private volatile HttpHost mCurrentHost;
+ private volatile Request mNewRequest;
private int mId;
Connection mConnection;
@@ -54,15 +56,25 @@ class ConnectionThread extends Thread {
mId = id;
mConnectionManager = connectionManager;
mRequestFeeder = requestFeeder;
+ mCurrentHost = null;
+ mNewRequest = null;
}
- void requestStop() {
+ public void requestStop() {
synchronized (mRequestFeeder) {
mRunning = false;
mRequestFeeder.notify();
}
}
+ public HttpHost getCurrentHost() {
+ return mCurrentHost;
+ }
+
+ public void setNewRequest(Request req) {
+ mNewRequest = req;
+ }
+
/**
* Loop until app shutdown. Runs connections in priority
* order.
@@ -87,7 +99,11 @@ class ConnectionThread extends Thread {
Request request;
/* Get a request to process */
- request = mRequestFeeder.getRequest();
+ if (mNewRequest != null) {
+ request = mNewRequest;
+ mNewRequest = null;
+ } else
+ request = mRequestFeeder.getRequest();
/* wait for work */
if (request == null) {
@@ -103,13 +119,18 @@ class ConnectionThread extends Thread {
mCurrentThreadTime = SystemClock
.currentThreadTimeMillis();
}
+ // Make sure the connection does not start to drain before the first request has been processed
}
} else {
if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " +
request.mHost + " " + request );
- mConnection = mConnectionManager.getConnection(mContext,
- request.mHost);
+ // ### this should possibly have some kind of lock to prevent the requestqueue from seeing the host as busy when it's not
+ mCurrentHost = request.mHost;
+ synchronized (this) {
+ mConnection = mConnectionManager.getConnection(mContext, request.mHost);
+ mConnection.setConnectionThread(this);
+ }
mConnection.processRequests(request);
if (mConnection.getCanPersist()) {
if (!mConnectionManager.recycleConnection(mConnection)) {
@@ -118,7 +139,12 @@ class ConnectionThread extends Thread {
} else {
mConnection.closeConnection();
}
- mConnection = null;
+ synchronized (this) {
+ mConnection.setConnectionThread(null);
+ mConnection = null;
+ }
+
+ mCurrentHost = null;
if (mCurrentThreadTime > 0) {
long start = mCurrentThreadTime;
diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java
index 09f6f4f..74c0de8 100644
--- a/core/java/android/net/http/Headers.java
+++ b/core/java/android/net/http/Headers.java
@@ -262,7 +262,14 @@ public final class Headers {
break;
case HASH_CACHE_CONTROL:
if (name.equals(CACHE_CONTROL)) {
- mHeaders[IDX_CACHE_CONTROL] = val;
+ // In case where we receive more than one header, create a ',' separated list.
+ // This should be ok, according to RFC 2616 chapter 4.2
+ if (mHeaders[IDX_CACHE_CONTROL] != null &&
+ mHeaders[IDX_CACHE_CONTROL].length() > 0) {
+ mHeaders[IDX_CACHE_CONTROL] += (',' + val);
+ } else {
+ mHeaders[IDX_CACHE_CONTROL] = val;
+ }
}
break;
case HASH_LAST_MODIFIED:
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index 8c0d503..0cca90b 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -71,6 +71,9 @@ class Request {
/** True if request has been cancelled */
volatile boolean mCancelled = false;
+ /** Priority */
+ volatile int mPriority = -1;
+
int mFailCount = 0;
// This will be used to set the Range field if we retry a connection. This
@@ -111,13 +114,15 @@ class Request {
Request(String method, HttpHost host, HttpHost proxyHost, String path,
InputStream bodyProvider, int bodyLength,
EventHandler eventHandler,
- Map<String, String> headers) {
+ Map<String, String> headers,
+ int pri) {
mEventHandler = eventHandler;
mHost = host;
mProxyHost = proxyHost;
mPath = path;
mBodyProvider = bodyProvider;
mBodyLength = bodyLength;
+ mPriority = pri;
if (bodyProvider == null && !"POST".equalsIgnoreCase(method)) {
mHttpRequest = new BasicHttpRequest(method, getUri());
diff --git a/core/java/android/net/http/RequestFeeder.java b/core/java/android/net/http/RequestFeeder.java
index 34ca267..739db27 100644
--- a/core/java/android/net/http/RequestFeeder.java
+++ b/core/java/android/net/http/RequestFeeder.java
@@ -29,6 +29,7 @@ interface RequestFeeder {
Request getRequest();
Request getRequest(HttpHost host);
+ Request peekRequest();
/**
* @return true if a request for this host is available
@@ -39,4 +40,5 @@ interface RequestFeeder {
* Put request back on head of queue
*/
void requeueRequest(Request request);
+ void requeueRequest(Request request, boolean commit, boolean notif);
}
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 103fd94..07533ca 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -456,6 +456,6 @@ public class RequestHandle {
mRequest = mRequestQueue.queueRequest(
mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
mBodyProvider,
- mBodyLength).mRequest;
+ mBodyLength, -1, false).mRequest;
}
}
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
index a31639f..50ea7f5 100644
--- a/core/java/android/net/http/RequestQueue.java
+++ b/core/java/android/net/http/RequestQueue.java
@@ -36,6 +36,9 @@ import android.text.TextUtils;
import android.util.Log;
import java.io.InputStream;
+import java.util.Comparator;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -57,6 +60,7 @@ public class RequestQueue implements RequestFeeder {
private final Context mContext;
private final ActivePool mActivePool;
private final ConnectivityManager mConnectivityManager;
+ private final HashSet<HttpHost> mPriorities;
private HttpHost mProxyHost = null;
private BroadcastReceiver mProxyChangeReceiver;
@@ -213,6 +217,7 @@ public class RequestQueue implements RequestFeeder {
mContext = context;
mPending = new LinkedHashMap<HttpHost, LinkedList<Request>>(32);
+ mPriorities = new HashSet<HttpHost>();
mActivePool = new ActivePool(connectionCount);
mActivePool.startup();
@@ -221,6 +226,58 @@ public class RequestQueue implements RequestFeeder {
context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
+ public synchronized boolean setRequestPriority(WebAddress uri, int priority) {
+ // ### this lookup won't work if a proxy is being used
+ HttpHost host = new HttpHost(uri.mHost, uri.mPort, uri.mScheme);
+ if (mPending.containsKey(host)) {
+ LinkedList<Request> reqList = mPending.get(host);
+ // ### O(n) lookup, certainly not ideal
+ ListIterator iter = reqList.listIterator(0);
+ while (iter.hasNext()) {
+ Request request = (Request)iter.next();
+ if (request.mPath.equals(uri.mPath)) {
+ request.mPriority = priority;
+ mPriorities.add(host);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void commitPrioritiesForList(LinkedList<Request> reqList) {
+ Collections.sort(reqList, new Comparator<Object>() {
+ public int compare(Object o1, Object o2) {
+ int r1 = ((Request)o1).mPriority;
+ int r2 = ((Request)o2).mPriority;
+
+ if (r1 == r2)
+ return 0;
+ else if (r1 == -1)
+ return 1;
+ else if (r2 == -1)
+ return -1;
+ else if (r1 < r2)
+ return -1;
+ return 1;
+ }
+ });
+ }
+
+ public synchronized void commitRequestPriorities() {
+ if (mPriorities.isEmpty())
+ return;
+ Iterator iter = mPriorities.iterator();
+ while (iter.hasNext()) {
+ HttpHost host = (HttpHost)iter.next();
+ if (mPending.containsKey(host)) {
+ LinkedList<Request> reqList = mPending.get(host);
+ commitPrioritiesForList(reqList);
+ }
+ }
+ mPriorities.clear();
+ }
+
/**
* Enables data state and proxy tracking
*/
@@ -297,9 +354,17 @@ public class RequestQueue implements RequestFeeder {
String url, String method,
Map<String, String> headers, EventHandler eventHandler,
InputStream bodyProvider, int bodyLength) {
+ return queueRequest(url, method, headers, eventHandler,
+ bodyProvider, bodyLength, -1, false);
+ }
+
+ public RequestHandle queueRequest(
+ String url, String method,
+ Map<String, String> headers, EventHandler eventHandler,
+ InputStream bodyProvider, int bodyLength, int pri, boolean commit) {
WebAddress uri = new WebAddress(url);
return queueRequest(url, uri, method, headers, eventHandler,
- bodyProvider, bodyLength);
+ bodyProvider, bodyLength, pri, commit);
}
/**
@@ -316,7 +381,7 @@ public class RequestQueue implements RequestFeeder {
public RequestHandle queueRequest(
String url, WebAddress uri, String method, Map<String, String> headers,
EventHandler eventHandler,
- InputStream bodyProvider, int bodyLength) {
+ InputStream bodyProvider, int bodyLength, int pri, boolean commit) {
if (HttpLog.LOGV) HttpLog.v("RequestQueue.queueRequest " + uri);
@@ -331,9 +396,9 @@ public class RequestQueue implements RequestFeeder {
// set up request
req = new Request(method, httpHost, mProxyHost, uri.mPath, bodyProvider,
- bodyLength, eventHandler, headers);
+ bodyLength, eventHandler, headers, pri);
- queueRequest(req, false);
+ queueRequest(req, false, commit);
mActivePool.mTotalRequest++;
@@ -359,12 +424,18 @@ public class RequestQueue implements RequestFeeder {
public Request getRequest(HttpHost host) {
return getRequest();
}
+ public Request peekRequest() {
+ return mRequest;
+ }
public boolean haveRequest(HttpHost host) {
return mRequest != null;
}
public void requeueRequest(Request r) {
mRequest = r;
}
+ public void requeueRequest(Request r, boolean commit, boolean notif) {
+ requeueRequest(r);
+ }
}
public RequestHandle queueSynchronousRequest(String url, WebAddress uri,
@@ -378,7 +449,7 @@ public class RequestQueue implements RequestFeeder {
HttpHost host = new HttpHost(uri.mHost, uri.mPort, uri.mScheme);
Request req = new Request(method, host, mProxyHost, uri.mPath,
- bodyProvider, bodyLength, eventHandler, headers);
+ bodyProvider, bodyLength, eventHandler, headers, 0);
// Open a new connection that uses our special RequestFeeder
// implementation.
@@ -444,16 +515,55 @@ public class RequestQueue implements RequestFeeder {
HttpLog.v(dump.toString());
}
+ private Map.Entry<HttpHost, LinkedList<Request>> priorityList() {
+ int curPri = -1;
+ int entryPri;
+ Map.Entry<HttpHost, LinkedList<Request>> ret = null;
+ if (!mPending.isEmpty()) {
+ Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter = mPending.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next();
+ if (ret == null) {
+ ret = entry;
+ }
+ entryPri = entry.getValue().getFirst().mPriority;
+ if (entryPri != -1 && (curPri == -1 || curPri > entryPri)) {
+ ret = entry;
+ curPri = entryPri;
+ }
+ }
+ }
+ return ret;
+ }
+
+ public synchronized Request peekRequest() {
+ Request ret = null;
+
+ Map.Entry<HttpHost, LinkedList<Request>> entry = priorityList();
+ if (entry != null && !entry.getValue().isEmpty()) {
+ if (entry.getValue().getFirst().mPriority != -1)
+ ret = entry.getValue().getFirst();
+ }
+
+ return ret;
+ }
+
/*
* RequestFeeder implementation
*/
public synchronized Request getRequest() {
Request ret = null;
- if (!mPending.isEmpty()) {
- ret = removeFirst(mPending);
+ Map.Entry<HttpHost, LinkedList<Request>> entry = priorityList();
+ if (entry != null) {
+ LinkedList<Request> reqList = entry.getValue();
+ ret = reqList.removeFirst();
+ if (reqList.isEmpty()) {
+ mPending.remove(entry.getKey());
+ }
}
if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest() => " + ret);
+
return ret;
}
@@ -485,7 +595,13 @@ public class RequestQueue implements RequestFeeder {
* Put request back on head of queue
*/
public void requeueRequest(Request request) {
- queueRequest(request, true);
+ requeueRequest(request, true, true);
+ }
+
+ public void requeueRequest(Request request, boolean commit, boolean notif) {
+ queueRequest(request, true, commit);
+ if (notif)
+ mActivePool.startConnectionThread();
}
/**
@@ -495,7 +611,7 @@ public class RequestQueue implements RequestFeeder {
mActivePool.shutdown();
}
- protected synchronized void queueRequest(Request request, boolean head) {
+ protected synchronized void queueRequest(Request request, boolean head, boolean commit) {
HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost;
LinkedList<Request> reqList;
if (mPending.containsKey(host)) {
@@ -509,6 +625,11 @@ public class RequestQueue implements RequestFeeder {
} else {
reqList.add(request);
}
+ if (commit && request.mPriority != -1) {
+ commitPrioritiesForList(reqList);
+ } else if (!commit && request.mPriority != -1) {
+ mPriorities.add(host);
+ }
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2e14667..86f9a6b 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -94,7 +94,8 @@ public final class Debug
/**
* Default trace file path and file
*/
- private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/";
+ private static final String DEFAULT_TRACE_PATH_PREFIX =
+ Environment.getExternalStorageDirectory().getPath() + "/";
private static final String DEFAULT_TRACE_BODY = "dmtrace";
private static final String DEFAULT_TRACE_EXTENSION = ".trace";
private static final String DEFAULT_TRACE_FILE_PATH =
@@ -127,7 +128,7 @@ public final class Debug
public int otherPrivateDirty;
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;
-
+
public MemoryInfo() {
}
@@ -137,21 +138,21 @@ public final class Debug
public int getTotalPss() {
return dalvikPss + nativePss + otherPss;
}
-
+
/**
* Return total private dirty memory usage in kB.
*/
public int getTotalPrivateDirty() {
return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty;
}
-
+
/**
* Return total shared dirty memory usage in kB.
*/
public int getTotalSharedDirty() {
return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
}
-
+
public int describeContents() {
return 0;
}
@@ -179,7 +180,7 @@ public final class Debug
otherPrivateDirty = source.readInt();
otherSharedDirty = source.readInt();
}
-
+
public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
public MemoryInfo createFromParcel(Parcel source) {
return new MemoryInfo(source);
@@ -460,7 +461,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* Like startMethodTracing(String, int, int), but taking an already-opened
* FileDescriptor in which the trace is written. The file name is also
* supplied simply for logging. Makes a dup of the file descriptor.
- *
+ *
* Not exposed in the SDK unless we are really comfortable with supporting
* this and find it would be useful.
* @hide
@@ -1070,7 +1071,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* static {
* // Sets all the fields
* Debug.setFieldsOn(MyDebugVars.class);
- *
+ *
* // Sets only the fields annotated with @Debug.DebugProperty
* // Debug.setFieldsOn(MyDebugVars.class, true);
* }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 01cc408..90ef1cb 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -39,4 +39,11 @@ interface IPowerManager
// sets the brightness of the backlights (screen, keyboard, button) 0-255
void setBacklightBrightness(int brightness);
void setAttentionLight(boolean on, int color);
+
+ // custom backlight things
+ int getLightSensorValue();
+ int getRawLightSensorValue();
+ int getLightSensorScreenBrightness();
+ int getLightSensorButtonBrightness();
+ int getLightSensorKeyboardBrightness();
}
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index f842d75..f44cbe4 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -39,6 +39,7 @@ public class ListPreference extends DialogPreference {
private CharSequence[] mEntries;
private CharSequence[] mEntryValues;
private String mValue;
+ private String mSummary;
private int mClickedDialogEntryIndex;
public ListPreference(Context context, AttributeSet attrs) {
@@ -49,8 +50,16 @@ public class ListPreference extends DialogPreference {
mEntries = a.getTextArray(com.android.internal.R.styleable.ListPreference_entries);
mEntryValues = a.getTextArray(com.android.internal.R.styleable.ListPreference_entryValues);
a.recycle();
+
+ /* Retrieve the Preference summary attribute since it's private
+ * in the Preference class.
+ */
+ a = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Preference, 0, 0);
+ mSummary = a.getString(com.android.internal.R.styleable.Preference_summary);
+ a.recycle();
}
-
+
public ListPreference(Context context) {
this(context, null);
}
@@ -127,6 +136,43 @@ public class ListPreference extends DialogPreference {
}
/**
+ * Returns the summary of this ListPreference. If the summary
+ * has a {@linkplain java.lang.String#format String formatting}
+ * marker in it (i.e. "%s" or "%1$s"), then the current entry
+ * value will be substituted in its place.
+ *
+ * @return the summary with appropriate string substitution
+ */
+ @Override
+ public CharSequence getSummary() {
+ final CharSequence entry = getEntry();
+ if (mSummary == null || entry == null) {
+ return super.getSummary();
+ } else {
+ return String.format(mSummary, entry);
+ }
+ }
+
+ /**
+ * Sets the summary for this Preference with a CharSequence.
+ * If the summary has a
+ * {@linkplain java.lang.String#format String formatting}
+ * marker in it (i.e. "%s" or "%1$s"), then the current entry
+ * value will be substituted in its place when it's retrieved.
+ *
+ * @param summary The summary for the preference.
+ */
+ @Override
+ public void setSummary(CharSequence summary) {
+ super.setSummary(summary);
+ if (summary == null && mSummary != null) {
+ mSummary = null;
+ } else if (summary != null && !summary.equals(mSummary)) {
+ mSummary = summary.toString();
+ }
+ }
+
+ /**
* Sets the value to the given index from the entry values.
*
* @param index The index of the value to set.
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 2fba1d7..9c3a725 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -342,6 +343,34 @@ public class Browser {
}
/**
+ * Returns top num of visited URLs in the history.
+ * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
+ * @param cr The ContentResolver used to access the database.
+ * @hide pending API council approval
+ */
+ public static final String[] getVisitedHistoryByOrder(ContentResolver cr, String order, int num) {
+ try {
+ String[] projection = new String[] {
+ "url"
+ };
+ Cursor c = cr.query(BOOKMARKS_URI, projection, "visits > 0", null,
+ order);
+
+ int count = (c.getCount() > num)? num:c.getCount();
+ String[] str = new String[count];
+ int i = 0;
+ while ((i<count) && c.moveToNext()) {
+ str[i] = c.getString(0);
+ i++;
+ }
+ c.deactivate();
+ return str;
+ } catch (IllegalStateException e) {
+ return new String[0];
+ }
+ }
+
+ /**
* If there are more than MAX_HISTORY_COUNT non-bookmark history
* items in the bookmark/history table, delete TRUNCATE_N_OLDEST
* of them. This is used to keep our history table to a
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e12dfb0..9cd0d3a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1271,6 +1271,136 @@ public final class Settings {
public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
/**
+ * Indicates that custom light sensor settings has changed.
+ * The value is random and changes reloads light settings.
+ *
+ * @hide
+ */
+ public static final String LIGHTS_CHANGED = "lights_changed";
+
+ /**
+ * Whether custom light sensor levels & values are enabled. The value is
+ * boolean (1 or 0).
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_CUSTOM = "light_sensor_custom";
+
+ /**
+ * Screen dim value to use if LIGHT_SENSOR_CUSTOM is set. The value is int.
+ * Default is android.os.BRIGHTNESS_DIM.
+ *
+ * @hide
+ */
+ public static final String LIGHT_SCREEN_DIM = "light_screen_dim";
+
+ /**
+ * Custom light sensor levels. The value is a comma separated int array
+ * with length N.
+ * Example: "100,300,3000".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_LEVELS = "light_sensor_levels";
+
+ /**
+ * Custom light sensor lcd values. The value is a comma separated int array
+ * with length N+1.
+ * Example: "10,50,100,255".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_LCD_VALUES = "light_sensor_lcd_values";
+
+ /**
+ * Custom light sensor lcd values. The value is a comma separated int array
+ * with length N+1.
+ * Example: "10,50,100,255".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_BUTTON_VALUES = "light_sensor_button_values";
+
+ /**
+ * Custom light sensor lcd values. The value is a comma separated int array
+ * with length N+1.
+ * Example: "10,50,100,255".
+ *
+ * @hide
+ */
+ public static final String LIGHT_SENSOR_KEYBOARD_VALUES = "light_sensor_keyboard_values";
+
+ /**
+ * Whether light sensor is allowed to decrease when calculating automatic
+ * backlight. The value is boolean (1 or 0).
+ *
+ * @hide
+ */
+ public static final String LIGHT_DECREASE = "light_decrease";
+
+ /**
+ * Light sensor hysteresis for decreasing backlight. The value is
+ * int (0-99) representing % (0-0.99 as float). Example:
+ *
+ * Levels Output
+ * 0 - 100 50
+ * 100 - 200 100
+ * 200 - Inf 255
+ *
+ * Current sensor value is 150 which gives light value 100. Hysteresis is 50.
+ * Current level lower bound is 100 and previous lower bound is 0.
+ * Sensor value must drop below 100-(100-0)*(50/100)=50 for output to become 50
+ * (corresponding to the 0 - 100 level).
+ * @hide
+ */
+ public static final String LIGHT_HYSTERESIS = "light_hysteresis";
+
+ /**
+ * Whether light sensor used when calculating automatic backlight should
+ * be filtered through an moving average filter.
+ * The value is boolean (1 or 0).
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER = "light_filter";
+
+ /**
+ * Window length of filter used when calculating automatic backlight.
+ * One minute means that the average sensor value last minute is used.
+ * The value is integer (milliseconds)
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER_WINDOW = "light_filter_window";
+
+ /**
+ * Reset threshold of filter used when calculating automatic backlight.
+ * Sudden large jumps in sensor value resets the filter. This is used
+ * to make the filter respond quickly to large enough changes in input
+ * while still filtering small changes. Example:
+ *
+ * Current filter value (average) is 100 and sensor value is changing to
+ * 10, 150, 100, 30, 50. The filter is continously taking the average of
+ * the samples. Now the user goes outside and the value jumps over 1000.
+ * The difference between current average and new sample is larger than
+ * the reset threshold and filter is reset. It begins calculating a new
+ * average on samples around 1000 (say, 800, 1200, 1000, 1100 etc.)
+ *
+ * The value is integer (lux)
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER_RESET = "light_filter_reset";
+
+ /**
+ * Sample interval of filter used when calculating automatic backlight.
+ * The value is integer (milliseconds)
+ *
+ * @hide
+ */
+ public static final String LIGHT_FILTER_INTERVAL = "light_filter_interval";
+
+ /**
* Control whether the process CPU usage meter should be shown.
*/
public static final String SHOW_PROCESSES = "show_processes";
@@ -1526,14 +1656,214 @@ public final class Settings {
public static final String FANCY_IME_ANIMATIONS = "fancy_ime_animations";
/**
+ * Whether WebViews reflow content when zooming in by pinching. The value is
+ * boolean (1 or 0).
+ * @hide
+ */
+ public static final String WEB_VIEW_PINCH_REFLOW = "web_view_pinch_reflow";
+
+ /**
* Control whether the accelerometer will be used to change screen
* orientation. If 0, it will not be used unless explicitly requested
* by the application; if 1, it will be used by default unless explicitly
* disabled by the application.
*/
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
+
+ /**
+ * Control the type of rotation which can be performed using the accelerometer
+ * if ACCELEROMETER_ROTATION is enabled.
+ * Value is a bitwise combination of
+ * 1 = 90 degrees (left)
+ * 2 = 180 degrees (inverted)
+ * 4 = 270 degrees (right)
+ * Normal portrait (0 degrees) is always enabled
+ * Default is 5 (90 & 270 degrees) like stock Froyo
+ * @hide
+ */
+ public static final String ACCELEROMETER_ROTATION_MODE = "accelerometer_rotation_mode";
+
+ /**
+ * Specifies the number of recent apps to show (8, 12, 16)
+ * @hide
+ */
+ public static final String RECENT_APPS_NUMBER = "recent_apps_number";
+
+ /**
+ * Specifies the number of recent apps to show (8, 12, 16)
+ * @hide
+ */
+ public static final String RECENT_APPS_SHOW_TITLE = "recent_apps_show_title";
+
+ /**
+ * Specifies whether or not to use a custom app instead of the recent applications dialog
+ * @hide
+ */
+ public static final String USE_CUSTOM_APP = "use_custom_app";
+
+ /**
+ * Stores the uri of the custom application to use
+ * @hide
+ */
+ public static final String SELECTED_CUSTOM_APP = "selected_custom_app";
+
+ /**
+ * Toggles whether to display the PLMN field on the Lockscreen
+ * @hide
+ */
+ public static final String SHOW_PLMN_LS = "show_plmn_ls";
+
+ /**
+ * Toggles whether to display the SPN field on the Lockscreen
+ * @hide
+ */
+ public static final String SHOW_SPN_LS = "show_spn_ls";
+
+ /**
+ * Toggles whether to display the PLMN field on the Notification bar
+ * @hide
+ */
+ public static final String SHOW_PLMN_SB = "show_plmn_sb";
+
+ /**
+ * Toggles whether to display the SPN field on the Notification bar
+ * @hide
+ */
+ public static final String SHOW_SPN_SB = "show_spn_sb";
+
+ /**
+ * Specifies whether to show or hide clock
+ * @hide
+ */
+ public static final String SHOW_STATUS_CLOCK = "show_status_clock";
+
+ /**
+ * Specifies the clock color
+ * @hide
+ */
+ public static final String CLOCK_COLOR = "clock_color";
+
+ /**
+ * Specifies whether to show or hide the dbm signal level
+ * @hide
+ */
+ public static final String SHOW_STATUS_DBM = "show_status_dbm";
+
+ /**
+ * Specifies the dbm signal level color
+ * @hide
+ */
+ public static final String DBM_COLOR = "dbm_color";
+
+ /**
+ * Specifies whether to prompt on the power dialog
+ * @hide
+ */
+ public static final String POWER_DIALOG_PROMPT = "power_dialog_prompt";
+
+ /**
+ * Specifies notification count color
+ * @hide
+ */
+ public static final String NOTIF_COUNT_COLOR = "notifications_count_color";
+
+ /**
+ * Specifies the date color
+ * @hide
+ */
+ public static final String DATE_COLOR = "date_color";
+
+ /**
+ * Specifies new notification ticker color
+ * @hide
+ */
+ public static final String NEW_NOTIF_TICKER_COLOR = "new_notifications_ticker_color";
+
+ /**
+ * Specifies no notifications color
+ * @hide
+ */
+ public static final String NO_NOTIF_COLOR = "no_notifications_color";
+
+ /**
+ * Specifies latest nofitication color
+ * @hide
+ */
+ public static final String LATEST_NOTIF_COLOR = "latest_notifications_color";
+
+ /**
+ * Specifies ongoing notification color
+ * @hide
+ */
+ public static final String ONGOING_NOTIF_COLOR = "ongoing_notifications_color";
+
+ /**
+ * Specifies spn label color
+ * @hide
+ */
+ public static final String SPN_LABEL_COLOR = "spn_label_color";
+
+ /**
+ * Specifies plmn color
+ * @hide
+ */
+ public static final String PLMN_LABEL_COLOR = "plmn_label_color";
+
+ /**
+ * Specifies clear button color
+ * @hide
+ */
+ public static final String CLEAR_BUTTON_LABEL_COLOR = "clear_button_label_color";
+
+ /**
+ * Specifies notification item title color.
+ * @hide
+ */
+ public static final String NOTIF_ITEM_TITLE_COLOR = "notifications_title_color";
+
+ /**
+ * Specifies notification item text color.
+ * @hide
+ */
+ public static final String NOTIF_ITEM_TEXT_COLOR = "notifications_text_color";
+
+ /**
+ * Specifies notification item time color.
+ * @hide
+ */
+ public static final String NOTIF_ITEM_TIME_COLOR = "notifications_time_color";
/**
+ * Whether to show the battery level percentage overlayed on the icon.
+ * @hide
+ */
+ public static final String BATTERY_PERCENTAGE_STATUS_ICON = "battery_percentage_status_icon";
+
+ /**
+ * Specifies battery percentage status color
+ * @hide
+ */
+ public static final String BATTERY_PERCENTAGE_STATUS_COLOR = "battery_status_color_title";
+
+ /**
+ * Specifies whether to show AM/PM indicators for 12-hour clock
+ * @hide
+ */
+ public static final String SHOW_TWELVE_HOUR_CLOCK_PERIOD = "show_clock_period";
+
+ /**
+ * How many ms to delay before enabling the screen lock when the screen goes off due to timeout
+ * @hide
+ */
+ public static final String SCREEN_LOCK_TIMEOUT_DELAY = "screen_lock_timeout_delay";
+
+ /**
+ * How many ms to delay before enabling the screen lock when the screen is turned off by the user
+ * @hide
+ */
+ public static final String SCREEN_LOCK_SCREENOFF_DELAY = "screen_lock_screenoff_delay";
+
+ /**
* Whether the audible DTMF tones are played by the dialer when dialing. The value is
* boolean (1 or 0).
*/
@@ -1596,6 +1926,72 @@ public final class Settings {
public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
/**
+ * Whether haptic feedback is enabled on virtual key release (as opposed to pressed)
+ * boolean (1 or 0).
+ * @hide
+ */
+ public static final String HAPTIC_FEEDBACK_UP_ENABLED = "haptic_feedback_up_enabled";
+
+ /**
+ * Whether haptic is also activated for all screen interaction (follows Sound Effects Enabled behaviour)
+ * boolean (1 or 0).
+ * @hide
+ */
+ public static final String HAPTIC_FEEDBACK_ALL_ENABLED = "haptic_feedback_all_enabled";
+
+ /**
+ * Value for haptic down (string will be converted to array -
+ * format is ***"delay in msec before turning on"_"delay in msec before turning off__**repeat**)
+ * @hide
+ */
+ public static final String HAPTIC_DOWN_ARRAY = "haptic_down_array";
+
+ /**
+ * Value for haptic up - same format as _DOWN_ARRAY
+ * @hide
+ */
+ public static final String HAPTIC_UP_ARRAY = "haptic_up_array";
+
+ /**
+ * Value for long presses - same format as _DOWN_ARRAY
+ * @hide
+ */
+ public static final String HAPTIC_LONG_ARRAY = "haptic_long_array";
+
+ /**
+ * these store the ORIGINAL default haptic values from config.xml
+ * this is so HapticAdjust can easily pull them when resetting defaults
+ * these are created and acted on in PhoneWindowManager
+ * @hide
+ */
+ public static final String HAPTIC_DOWN_ARRAY_DEFAULT = "haptic_down_array_default";
+
+ /**
+ * Same as HAPTIC_DOWN_ARRAY_DEFAULT but for key releases
+ * @hide
+ */
+ public static final String HAPTIC_UP_ARRAY_DEFAULT = "haptic_up_array_default";
+
+ /**
+ * Same as HAPTIC_DOWN_ARRAY_DEFAULT but for key releases
+ * @hide
+ */
+ public static final String HAPTIC_LONG_ARRAY_DEFAULT = "haptic_long_array_default";
+
+ /**
+ * Set values for haptic feedback from typing on keypad (new for Froyo)
+ * @hide
+ */
+ public static final String HAPTIC_TAP_ARRAY = "haptic_tap_array";
+
+ /**
+ * Default values for haptic feedback from typing on keypad (new for Froyo) - pulled
+ * from config.xml
+ * @hide
+ */
+ public static final String HAPTIC_TAP_ARRAY_DEFAULT = "haptic_tap_array_default";
+
+ /**
* Whether live web suggestions while the user types into search dialogs are
* enabled. Browsers and other search UIs should respect this, as it allows
* a user to avoid sending partial queries to a search engine, if it poses
@@ -1679,6 +2075,114 @@ public final class Settings {
public static final String UNLOCK_SOUND = "unlock_sound";
/**
+ * Whether to wake the screen with the trackball. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String TRACKBALL_WAKE_SCREEN = "trackball_wake_screen";
+
+ /**
+ * Whether to unlock the screen with the trackball. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String TRACKBALL_UNLOCK_SCREEN = "trackball_unlock_screen";
+
+ /**
+ * Pulse the Trackball with Screen On. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String TRACKBALL_SCREEN_ON = "trackball_screen_on";
+
+ /**
+ * Pulse notifications in Succession. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String TRACKBALL_NOTIFICATION_SUCCESSION = "trackball_sucession";
+
+ /**
+ * Pulse notifications in Succession. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String TRACKBALL_NOTIFICATION_RANDOM = "trackball_random_colors";
+
+ /**
+ * Pulse notifications in Succession. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String TRACKBALL_NOTIFICATION_PULSE_ORDER = "trackball_pulse_in_order";
+
+ /**
+ * Beldn Notification Colors. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String TRACKBALL_NOTIFICATION_BLEND_COLOR = "trackball_blend_color";
+
+ /**
+ * Trackball Notification Colors. The value is String pkg=color|pkg=color
+ * @hide
+ */
+ public static final String NOTIFICATION_PACKAGE_COLORS = "|";
+
+ /**
+ * Trackball Notification List. The value is String pkg|pkg
+ * @hide
+ */
+ public static final String NOTIFICATION_PACKAGE_LIST = "|";
+
+ /**
+ * Trackball Notification Colors Debugging. The value is boolean (1 or 0)
+ * @hide
+ */
+ public static final String NOTIFICATION_PACKAGE_COLORS_GET_PACK = "0";
+
+ /**
+ * Whether to unlock the menu key. The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String MENU_UNLOCK_SCREEN = "menu_unlock_screen";
+
+ /**
+ * Color mask tp apply to notification bar when custom is set
+ * @hide
+ */
+ public static final String NOTIF_BAR_COLOR = "notif_bar_color";
+
+ /**
+ * Whether to use custom notification bar
+ * @hide
+ */
+ public static final String NOTIF_BAR_CUSTOM = "notif_bar_custom";
+
+ /**
+ * Whether to use custom notification bar
+ * @hide
+ */
+ public static final String LOCKSCREEN_MUSIC_CONTROLS = "lockscreen_music_controls";
+
+ /**
+ * Whether to use custom notification bar
+ * @hide
+ */
+ public static final String LOCKSCREEN_ALWAYS_MUSIC_CONTROLS = "lockscreen_always_music_controls";
+
+ /**
+ * Whether to use a custom pull-down notification screen
+ * @hide
+ */
+ public static final String NOTIF_EXPANDED_BAR_COLOR = "notif_expanded_bar_color";
+
+ /**
+ * Color mask to apply to pull-down notification screen
+ * @hide
+ */
+ public static final String NOTIF_EXPANDED_BAR_CUSTOM = "notif_expanded_bar_custom";
+
+ /**
+ * Whether to keep the home app at a higher OOM adjustement
+ * @hide
+ */
+ public static final String LOCK_HOME_IN_MEMORY = "lock_home_in_memory";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
* @hide
@@ -1738,7 +2242,21 @@ public final class Settings {
DOCK_SOUNDS_ENABLED,
LOCKSCREEN_SOUNDS_ENABLED,
SHOW_WEB_SUGGESTIONS,
- NOTIFICATION_LIGHT_PULSE
+ NOTIFICATION_LIGHT_PULSE,
+ HAPTIC_FEEDBACK_UP_ENABLED,
+ HAPTIC_FEEDBACK_ALL_ENABLED,
+ HAPTIC_DOWN_ARRAY,
+ HAPTIC_UP_ARRAY,
+ HAPTIC_LONG_ARRAY,
+ HAPTIC_DOWN_ARRAY_DEFAULT,
+ HAPTIC_UP_ARRAY_DEFAULT,
+ HAPTIC_LONG_ARRAY_DEFAULT,
+ HAPTIC_TAP_ARRAY,
+ HAPTIC_TAP_ARRAY_DEFAULT,
+ NOTIF_BAR_COLOR,
+ NOTIF_BAR_CUSTOM,
+ NOTIF_EXPANDED_BAR_COLOR,
+ NOTIF_EXPANDED_BAR_CUSTOM
};
// Settings moved to Settings.Secure
@@ -2237,6 +2755,12 @@ public final class Settings {
public static final String ADB_ENABLED = "adb_enabled";
/**
+ * Whether to show ADB notifications.
+ * @hide
+ */
+ public static final String ADB_NOTIFY = "adb_notify";
+
+ /**
* Setting to allow mock locations and location provider status to be injected into the
* LocationManager service for testing purposes during application development. These
* locations and status values override actual location and status information generated
@@ -2275,6 +2799,14 @@ public final class Settings {
}
/**
+ * Get the key that retrieves a bluetooth hid device's priority.
+ * @hide
+ */
+ public static final String getBluetoothHidDevicePriorityKey(String address) {
+ return ("bluetooth_hid_device_priority_" + address.toUpperCase());
+ }
+
+ /**
* Whether or not data roaming is enabled. (0 = false, 1 = true)
*/
public static final String DATA_ROAMING = "data_roaming";
@@ -2341,6 +2873,48 @@ public final class Settings {
"lock_pattern_tactile_feedback_enabled";
/**
+ * LOCK_DOTS_VISIBLE
+ * @hide
+ */
+ public static final String LOCK_DOTS_VISIBLE = "lock_pattern_dotsvisible";
+
+ /**
+ * LOCK_SHOW_ERROR_PATH
+ * @hide
+ */
+ public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path";
+
+ /**
+ * LOCK_INCORRECT_DELAY
+ * @hide
+ */
+ public static final String LOCK_INCORRECT_DELAY = "lock_pattern_incorrect_delay";
+
+ /**
+ * SHOW_UNLOCK_TEXT
+ * @hide
+ */
+ public static final String SHOW_UNLOCK_TEXT = "lock_pattern_show_unlock_text";
+
+ /**
+ * SHOW_UNLOCK_ERR_TEXT
+ * @hide
+ */
+ public static final String SHOW_UNLOCK_ERR_TEXT = "lock_pattern_show_unlock_err_text";
+
+ /**
+ * LOCK_SHOW_CUSTOM_MSG
+ * @hide
+ */
+ public static final String LOCK_SHOW_CUSTOM_MSG = "lock_screen_show_custom_msg";
+
+ /**
+ * LOCK_CUSTOM_MSG
+ * @hide
+ */
+ public static final String LOCK_CUSTOM_MSG = "lock_screen_custom_msg";
+
+ /**
* Whether assisted GPS should be enabled or not.
* @hide
*/
@@ -3360,6 +3934,13 @@ public final class Settings {
/**
+ * Whether to allow move of any app to external storage
+ * @hide
+ */
+ public static final String ALLOW_MOVE_ALL_APPS_EXTERNAL =
+ "allow_move_all_apps_external";
+
+ /**
* @hide
*/
public static final String[] SETTINGS_TO_BACKUP = {
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index bf9e854..d271e93 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -25,6 +25,7 @@ import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SqliteWrapper;
import android.net.Uri;
+import android.os.Environment;
import android.telephony.SmsMessage;
import android.text.TextUtils;
import android.util.Config;
@@ -1526,7 +1527,8 @@ public final class Telephony {
* which streams the captured image to the uri. Internally we write the media content
* to this file. It's named '.temp.jpg' so Gallery won't pick it up.
*/
- public static final String SCRAP_FILE_PATH = "/sdcard/mms/scrapSpace/.temp.jpg";
+ public static final String SCRAP_FILE_PATH =
+ Environment.getExternalStorageDirectory().getPath() + "/mms/scrapSpace/.temp.jpg";
}
public static final class Intents {
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 893db2e..1cac1cd 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -22,6 +22,8 @@
package android.server;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -35,6 +37,7 @@ import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
@@ -55,7 +58,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String BLUETOOTH_ENABLED = "bluetooth_enabled";
- private static final int MESSAGE_CONNECT_TO = 1;
+ private static final String ACTION_CONNECT_TO = "android.bluetooth_a2dp.action.CONNECT_TO";
private static final String PROPERTY_STATE = "State";
@@ -111,8 +114,24 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
// after a delay. We delay to avoid connection collisions,
// and to give other profiles such as HFP a chance to
// connect first.
- Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, device);
- mHandler.sendMessageDelayed(msg, 6000);
+ AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ Intent i = new Intent(ACTION_CONNECT_TO);
+ i.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
+ mgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 6000, pi);
+ }
+ } else if (action.equals(ACTION_CONNECT_TO)) {
+ // check bluetooth is still on, device is still preferred, and
+ // nothing is currently connected
+ if (mBluetoothService.isEnabled() &&
+ getSinkPriority(device) == BluetoothA2dp.PRIORITY_AUTO_CONNECT &&
+ lookupSinksMatchingStates(new int[] {
+ BluetoothA2dp.STATE_CONNECTING,
+ BluetoothA2dp.STATE_CONNECTED,
+ BluetoothA2dp.STATE_PLAYING,
+ BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) {
+ log("Auto-connecting A2DP to sink " + device);
+ connectSink(device);
}
} else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
synchronized (this) {
@@ -180,6 +199,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mIntentFilter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
+ mIntentFilter.addAction(ACTION_CONNECT_TO);
mContext.registerReceiver(mReceiver, mIntentFilter);
mAudioDevices = new HashMap<BluetoothDevice, Integer>();
@@ -201,23 +221,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_CONNECT_TO:
- BluetoothDevice device = (BluetoothDevice) msg.obj;
- // check bluetooth is still on, device is still preferred, and
- // nothing is currently connected
- if (mBluetoothService.isEnabled() &&
- getSinkPriority(device) == BluetoothA2dp.PRIORITY_AUTO_CONNECT &&
- lookupSinksMatchingStates(new int[] {
- BluetoothA2dp.STATE_CONNECTING,
- BluetoothA2dp.STATE_CONNECTED,
- BluetoothA2dp.STATE_PLAYING,
- BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) {
- log("Auto-connecting A2DP to sink " + device);
- connectSink(device);
- }
- break;
- }
}
};
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index c0e4600..b53779b 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +21,7 @@ import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHid;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
@@ -380,6 +382,13 @@ class BluetoothEventLoop {
mBluetoothService.setLinkTimeout(address, 8000);
}
} else {
+ // Check and clean-up if bonding is in progress
+ if (mBluetoothService.getBondState().getBondState(address) ==
+ BluetoothDevice.BOND_BONDING) {
+ mBluetoothService.getBondState().setBondState(address,
+ BluetoothDevice.BOND_NONE);
+ }
+
intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
}
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
@@ -555,6 +564,7 @@ class BluetoothEventLoop {
boolean authorized = false;
ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+ BluetoothHid hid = new BluetoothHid(mContext);
// Bluez sends the UUID of the local service being accessed, _not_ the
// remote service
@@ -569,6 +579,15 @@ class BluetoothEventLoop {
} else {
Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
}
+ } else if( mBluetoothService.isEnabled() && BluetoothUuid.isHid(uuid)) {
+ Log.i(TAG, "Allowing incoming HID connection from " + address);
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ authorized = hid.getHidDevicePriority(device) > BluetoothHid.PRIORITY_OFF;
+ if (authorized) {
+ Log.i(TAG, "Allowing incoming HID connection from " + address);
+ } else {
+ Log.i(TAG, "Rejecting incoming HID connection from " + address);
+ }
} else {
Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
}
diff --git a/core/java/android/server/BluetoothHidService.java b/core/java/android/server/BluetoothHidService.java
new file mode 100644
index 0000000..1fd2e04
--- /dev/null
+++ b/core/java/android/server/BluetoothHidService.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2009 ISB Corporation
+ * Copyright (C) 2010 0xlab
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * TODO: Move this to services.jar
+ * and make the contructor package private again.
+ * @hide
+ */
+
+package android.server;
+
+import android.bluetooth.BluetoothHid;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothUuid;
+import android.bluetooth.IBluetoothHid;
+import android.os.ParcelUuid;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+public class BluetoothHidService extends IBluetoothHid.Stub {
+ private static final String TAG = "BluetoothHidService";
+ private static final boolean DBG = false;
+
+ public static final String BLUETOOTH_HID_SERVICE = "bluetooth_hid";
+
+ private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
+ private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private static final String BLUETOOTH_ENABLED = "bluetooth_enabled";
+
+ private final Context mContext;
+ private final IntentFilter mIntentFilter;
+ private HashMap<BluetoothDevice, Integer> mHidDevices;
+ private final BluetoothService mBluetoothService;
+ private final BluetoothAdapter mAdapter;
+
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ switch (state) {
+ case BluetoothAdapter.STATE_ON:
+ onBluetoothEnable();
+ break;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ onBluetoothDisable();
+ break;
+ }
+ } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
+ int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+ BluetoothDevice.ERROR);
+ switch(bondState) {
+ case BluetoothDevice.BOND_BONDED:
+ setHidDevicePriority(device, BluetoothHid.PRIORITY_ON);
+ break;
+ case BluetoothDevice.BOND_BONDING:
+ case BluetoothDevice.BOND_NONE:
+ setHidDevicePriority(device, BluetoothHid.PRIORITY_OFF);
+ break;
+ }
+ } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
+ synchronized (this) {
+ if (mHidDevices.containsKey(device)) {
+ int state = mHidDevices.get(device);
+ handleHIDStateChange(device, state, BluetoothHid.STATE_CONNECTED);
+ }
+ }
+ } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
+ synchronized (this) {
+ if (mHidDevices.containsKey(device)) {
+ int state = mHidDevices.get(device);
+ handleHIDStateChange(device, state, BluetoothHid.STATE_DISCONNECTED);
+ }
+ }
+ }
+ }
+ };
+
+
+ public BluetoothHidService(Context context, BluetoothService bluetoothService) {
+ mContext = context;
+
+ mBluetoothService = bluetoothService;
+ if (mBluetoothService == null) {
+ throw new RuntimeException("Platform does not support Bluetooth");
+ }
+
+ if (!initNative()) {
+ throw new RuntimeException("Could not init BluetoothHidService");
+ }
+
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
+ mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+ mContext.registerReceiver(mReceiver, mIntentFilter);
+
+ mHidDevices = new HashMap<BluetoothDevice, Integer>();
+
+ if (mBluetoothService.isEnabled())
+ onBluetoothEnable();
+ }
+
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ cleanupNative();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private boolean isHidDevice(BluetoothDevice device) {
+ ParcelUuid[] uuids = mBluetoothService.getRemoteUuids(device.getAddress());
+ if (uuids != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HID)) {
+ return true;
+ }
+ return false;
+ }
+
+ private synchronized boolean addHidDevice (BluetoothDevice device) {
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
+ String propValues[] = (String []) getHidPropertiesNative(path);
+ if (DBG) log("addHidDevice device = " + device);
+
+ if (propValues == null) {
+ Log.e(TAG, "Error while getting HID properties for device: " + device);
+ return false;
+ }
+ Integer state = null;
+ String name = propValues[0];
+ if (name.equals("Connected")) {
+ state = BluetoothHid.STATE_DISCONNECTED;
+ if (propValues[1].equals("true"))
+ state = BluetoothHid.STATE_CONNECTED;
+ }
+ mHidDevices.put(device, state);
+ handleHIDStateChange(device, BluetoothHid.STATE_DISCONNECTED, state);
+ return true;
+ }
+
+
+ private synchronized void onBluetoothEnable() {
+ String devices = mBluetoothService.getProperty("Devices");
+
+ if (devices != null) {
+ String [] paths = devices.split(",");
+ for (String path: paths) {
+ String address = mBluetoothService.getAddressFromObjectPath(path);
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ ParcelUuid[] remoteUuids = mBluetoothService.getRemoteUuids(address);
+ if (remoteUuids != null)
+ if (BluetoothUuid.containsAnyUuid(remoteUuids,
+ new ParcelUuid[] {BluetoothUuid.HID})) {
+ addHidDevice(device);
+ }
+ }
+ }
+ }
+
+ private synchronized void onBluetoothDisable() {
+ if (!mHidDevices.isEmpty()) {
+ BluetoothDevice[] devices = new BluetoothDevice[mHidDevices.size()];
+ devices = mHidDevices.keySet().toArray(devices);
+
+ for (BluetoothDevice device : devices) {
+ int state = mHidDevices.get(device);
+ switch (state) {
+ case BluetoothHid.STATE_CONNECTING:
+ case BluetoothHid.STATE_CONNECTED:
+ disconnectHidDeviceNative(mBluetoothService.getObjectPathFromAddress(
+ device.getAddress()));
+ handleHIDStateChange(device, state, BluetoothHid.STATE_DISCONNECTED);
+ break;
+ case BluetoothHid.STATE_DISCONNECTING:
+ handleHIDStateChange(device, BluetoothHid.STATE_DISCONNECTING,
+ BluetoothHid.STATE_DISCONNECTED);
+ break;
+ }
+ }
+ mHidDevices.clear();
+ }
+
+ }
+
+ public synchronized boolean connectHidDevice(BluetoothDevice device) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (DBG) log("connectHidDevice(" + device + ")");
+
+ // ignore if there are any active sinks
+ if (lookupSinksMatchingStates(new int[] {
+ BluetoothHid.STATE_CONNECTING,
+ BluetoothHid.STATE_CONNECTED,
+ BluetoothHid.STATE_DISCONNECTING}).size() != 0) {
+ return false;
+ }
+ if (mHidDevices.get(device) == null && !addHidDevice(device))
+ return false;
+
+ int state = mHidDevices.get(device);
+
+ switch (state) {
+ case BluetoothHid.STATE_CONNECTED:
+ case BluetoothHid.STATE_DISCONNECTING:
+ return false;
+ case BluetoothHid.STATE_CONNECTING:
+ return true;
+ }
+
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
+ if (path == null)
+ return false;
+
+ // State is DISCONNECTED
+ if (!connectHidDeviceNative(path)) {
+ return false;
+ }
+ return true;
+ }
+
+ public synchronized boolean disconnectHidDevice(BluetoothDevice device) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (DBG) log("disconnectHidDevice(" + device + ")");
+
+ if (mHidDevices.get(device) == null)
+ return false;
+
+ int state = mHidDevices.get(device);
+ switch (state) {
+ case BluetoothHid.STATE_DISCONNECTED:
+ return false;
+ case BluetoothHid.STATE_DISCONNECTING:
+ return true;
+ }
+
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
+ if (path == null) {
+ return false;
+ }
+
+ if (!disconnectHidDeviceNative(path)) {
+ return false;
+ }
+ return true;
+ }
+
+ public synchronized BluetoothDevice[] getConnectedSinks() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
+ new int[] {BluetoothHid.STATE_CONNECTED});
+ return sinks.toArray(new BluetoothDevice[sinks.size()]);
+ }
+
+ public synchronized BluetoothDevice[] getNonDisconnectedSinks() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
+ new int[] {BluetoothHid.STATE_CONNECTED,
+ BluetoothHid.STATE_CONNECTING,
+ BluetoothHid.STATE_DISCONNECTING});
+ return sinks.toArray(new BluetoothDevice[sinks.size()]);
+ }
+
+ public synchronized int getHidDeviceState(BluetoothDevice device) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ Integer state = mHidDevices.get(device);
+ if (state == null){
+ return BluetoothHid.STATE_DISCONNECTED;
+ }
+ return state;
+ }
+
+ public synchronized int getHidDevicePriority(BluetoothDevice device) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.getBluetoothHidDevicePriorityKey(device.getAddress()),
+ BluetoothHid.PRIORITY_UNDEFINED);
+ }
+
+
+ public synchronized boolean setHidDevicePriority(BluetoothDevice device, int priority) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
+ return false;
+ }
+ return Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.getBluetoothHidDevicePriorityKey(device.getAddress()), priority);
+
+ }
+
+
+ public synchronized void onPropertyChanged(String path, String []propValues) {
+ if (!mBluetoothService.isEnabled()) {
+ return;
+ }
+
+ String name = propValues[0];
+ String address = mBluetoothService.getAddressFromObjectPath(path);
+
+ if (address == null) {
+ Log.e(TAG, "onPropertyChanged: Address of the remote device in null");
+ return;
+ }
+
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ if (DBG) log("HID Device property changed: " + address + " property: " + name);
+
+ if (name.equals("Connected")) {
+ int state = BluetoothHid.STATE_DISCONNECTED;
+ if (propValues[1].equals("true")) {
+ state = BluetoothHid.STATE_CONNECTED;
+ }
+ if (mHidDevices.get(device) == null) {
+ // This is for an incoming connection for a device not known to us.
+ // We have authorized it and bluez state has changed.
+ addHidDevice(device);
+ } else {
+ int prevState = mHidDevices.get(device);
+ handleHIDStateChange(device, prevState, state);
+ }
+ }
+
+ }
+
+ private void handleHIDStateChange(BluetoothDevice device, int prevState, int state) {
+
+ if(DBG) log("HID device: " + device + " State:" + prevState + "->" + state);
+
+ if (state != prevState) {
+ mHidDevices.put(device, state);
+
+ if (getHidDevicePriority(device) > BluetoothHid.PRIORITY_OFF &&
+ state == BluetoothHid.STATE_CONNECTING ||
+ state == BluetoothHid.STATE_CONNECTED) {
+ setHidDevicePriority(device, BluetoothHid.PRIORITY_AUTO_CONNECT);
+ }
+ Intent intent = new Intent(BluetoothHid.HID_DEVICE_STATE_CHANGED_ACTION);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ intent.putExtra(BluetoothHid.HID_DEVICE_PREVIOUS_STATE, prevState);
+ intent.putExtra(BluetoothHid.HID_DEVICE_STATE, state);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+ }
+
+ private synchronized Set<BluetoothDevice> lookupSinksMatchingStates(int[] states) {
+ Set<BluetoothDevice> sinks = new HashSet<BluetoothDevice>();
+ if (mHidDevices.isEmpty()) {
+ return sinks;
+ }
+ for (BluetoothDevice device: mHidDevices.keySet()) {
+ int sinkState = getHidDeviceState(device);
+ for (int state : states) {
+ if (state == sinkState) {
+ sinks.add(device);
+ break;
+ }
+ }
+ }
+ return sinks;
+ }
+
+ public synchronized void onHidDeviceConnected(String path) {
+ if (mHidDevices == null) return;
+
+ if (!mBluetoothService.isEnabled()) {
+ return;
+ }
+
+ String address = mBluetoothService.getAddressFromObjectPath(path);
+ if (address == null) {
+ Log.e(TAG, "onHidDeviceConnected: Address of the remote device in null");
+ return;
+ }
+
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ if(DBG) log(" onHidDeviceConnected device = " + device);
+ if (mHidDevices.containsKey(device)) {
+ int prevState = mHidDevices.get(device);
+ handleHIDStateChange(device, prevState, BluetoothHid.STATE_CONNECTED);
+ }
+
+ }
+
+ public synchronized void onHidDeviceDisconnected(String path) {
+ if (mHidDevices == null) return;
+
+ if (!mBluetoothService.isEnabled()) {
+ return;
+ }
+
+ String address = mBluetoothService.getAddressFromObjectPath(path);
+ if (address == null) {
+ Log.e(TAG, "onHidDeviceDisconnected: Address of the remote device in null");
+ return;
+ }
+
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ if(DBG) log(" onHidDeviceDisconnected device = " + device);
+ if (mHidDevices.containsKey(device)) {
+ int prevState = mHidDevices.get(device);
+ handleHIDStateChange(device, prevState, BluetoothHid.STATE_DISCONNECTED);
+ }
+ }
+
+ @Override
+ protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mHidDevices.isEmpty()) return;
+ pw.println("Cached hid devices:");
+ for (BluetoothDevice device : mHidDevices.keySet()) {
+ int state = mHidDevices.get(device);
+ pw.println(device + " " + BluetoothHid.stateToString(state));
+ }
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+
+ private native boolean initNative();
+ private native void cleanupNative();
+
+ private synchronized native boolean connectHidDeviceNative(String path);
+ private synchronized native boolean disconnectHidDeviceNative(String path);
+ private synchronized native Object []getHidPropertiesNative(String path);
+
+}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index c0affd3..7095dbe 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1167,7 +1168,13 @@ public class BluetoothService extends IBluetooth.Stub {
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
return false;
}
- return removeDeviceNative(getObjectPathFromAddress(address));
+
+ if (removeDeviceNative(getObjectPathFromAddress(address))) {
+ removeRemoteDeviceProperties(address);
+ return true;
+ }
+
+ return false;
}
public synchronized String[] listBonds() {
@@ -1275,6 +1282,7 @@ public class BluetoothService extends IBluetooth.Stub {
if (propVal != null) {
propVal.put(name, value);
mDeviceProperties.put(address, propVal);
+ Log.d(TAG, "setRemoteDeviceProperty addr = " + address + " name = " + name + " value = " + value);
} else {
Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 38ac9b7..4063aef 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -305,13 +305,13 @@ public abstract class Layout {
if (spans[n] instanceof LeadingMarginSpan) {
LeadingMarginSpan margin = (LeadingMarginSpan) spans[n];
- if (dir == DIR_RIGHT_TO_LEFT) {
- margin.drawLeadingMargin(c, paint, right, dir, ltop,
- lbaseline, lbottom, buf,
- start, end, isFirstParaLine, this);
-
- right -= margin.getLeadingMargin(isFirstParaLine);
- } else {
+ // if (dir == DIR_RIGHT_TO_LEFT) {
+ // margin.drawLeadingMargin(c, paint, right, dir, ltop,
+ // lbaseline, lbottom, buf,
+ // start, end, isFirstParaLine, this);
+ //
+ // right -= margin.getLeadingMargin(isFirstParaLine);
+ //} else {
margin.drawLeadingMargin(c, paint, left, dir, ltop,
lbaseline, lbottom, buf,
start, end, isFirstParaLine, this);
@@ -320,7 +320,7 @@ public abstract class Layout {
if (margin instanceof LeadingMarginSpan.LeadingMarginSpan2) {
int count = ((LeadingMarginSpan.LeadingMarginSpan2)margin).getLeadingMarginLineCount();
useMargin = count > i;
- }
+ // }
left += margin.getLeadingMargin(useMargin);
}
}
@@ -364,8 +364,7 @@ public abstract class Layout {
Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT);
Assert.assertNotNull(c);
}
- // XXX: assumes there's nothing additional to be done
- c.drawText(buf, start, end, x, lbaseline, paint);
+ c.drawText(buf, start, end, x, lbaseline, paint,false);
} else {
drawText(c, buf, start, end, dir, directions,
x, ltop, lbaseline, lbottom, paint, mWorkPaint,
@@ -1810,7 +1809,7 @@ public abstract class Layout {
public static class Directions {
private short[] mDirections;
- // The values in mDirections are the offsets from the first character
+ // The values in mDirections are the offsets from the last flip in direction
// in the line to the next flip in direction. Runs at even indices
// are left-to-right, the others are right-to-left. So, for example,
// a line that starts with a right-to-left run has 0 at mDirections[0],
@@ -1823,6 +1822,36 @@ public abstract class Layout {
/* package */ Directions(short[] dirs) {
mDirections = dirs;
}
+
+ static int baseDirection(Directions dir,int length) {
+ if (dir == DIRS_ALL_LEFT_TO_RIGHT) {
+ return DIR_LEFT_TO_RIGHT;
+ } else if (dir == DIRS_ALL_RIGHT_TO_LEFT) {
+ return DIR_RIGHT_TO_LEFT;
+ }
+
+ int sum=0;
+ int lastSwitch=0;
+ int i=0;
+ while ((i+1) < dir.mDirections.length) {
+ sum+=dir.mDirections[i];//-lastSwitch;
+ sum-=dir.mDirections[i+1];//-dir.mDirections[i];
+ lastSwitch=dir.mDirections[i+1];
+ i+=2;
+ }
+
+ if ((i+1)==dir.mDirections.length) {
+ sum+=dir.mDirections[i];//-lastSwitch);
+ } else if (i==dir.mDirections.length) {
+ sum-=length-lastSwitch;
+ }
+
+ if (sum>=0) {
+ return DIR_LEFT_TO_RIGHT;
+ } else {
+ return DIR_RIGHT_TO_LEFT;
+ }
+ }
}
/**
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index caaafa1..b6a9b17 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1042,14 +1042,14 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable,
checkRange("drawText", start, end);
if (end <= mGapStart) {
- c.drawText(mText, start, end - start, x, y, p);
+ c.drawText(mText, start, end - start, x, y, p,true);
} else if (start >= mGapStart) {
- c.drawText(mText, start + mGapLength, end - start, x, y, p);
+ c.drawText(mText, start + mGapLength, end - start, x, y, p,true);
} else {
char[] buf = TextUtils.obtain(end - start);
getChars(start, end, buf, 0);
- c.drawText(buf, 0, end - start, x, y, p);
+ c.drawText(buf, 0, end - start, x, y, p,true);
TextUtils.recycle(buf);
}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index f02ad2a..047e6156 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -689,6 +689,7 @@ extends Layout
if (cur ==
Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
+ else chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
}
}
@@ -777,7 +778,7 @@ extends Layout
cur = d;
if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- chInfo[j] = cur;
+ chInfo[j] = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
}
// dump(chdirs, n, "W7");
@@ -790,9 +791,10 @@ extends Layout
if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
cur = d;
- } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
- d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
+ } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+ } else if (d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
+ cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
} else {
byte dd = SOR;
int k;
@@ -804,8 +806,10 @@ extends Layout
dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
break;
}
- if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
- dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
+ if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
+ dd = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
+ break;
+ } else if (dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
dd = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
break;
}
@@ -1244,7 +1248,7 @@ extends Layout
}
public int getParagraphDirection(int line) {
- return mLines[mColumns * line + DIR] >> DIR_SHIFT;
+ return Directions.baseDirection(mLineDirections[line],getLineEnd(line)-getLineStart(line));
}
public boolean getLineContainsTab(int line) {
diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java
index 513b2cd..d2be383 100644
--- a/core/java/android/text/Styled.java
+++ b/core/java/android/text/Styled.java
@@ -129,7 +129,7 @@ public class Styled
}
canvas.drawText(tmp, tmpstart, tmpend,
- x - ret, y + workPaint.baselineShift, workPaint);
+ x - ret, y + workPaint.baselineShift, workPaint,false);
} else {
if (needWidth) {
if (!haveWidth) {
@@ -139,7 +139,7 @@ public class Styled
}
canvas.drawText(tmp, tmpstart, tmpend,
- x, y + workPaint.baselineShift, workPaint);
+ x, y + workPaint.baselineShift, workPaint,false);
}
} else {
if (needWidth && !haveWidth) {
@@ -261,13 +261,13 @@ public class Styled
if (canvas != null)
canvas.drawText(tmp, 0, tmpend,
- x - ret, y, paint);
+ x - ret, y, paint,false);
} else {
if (needWidth)
ret = paint.measureText(text, start, end);
if (canvas != null)
- canvas.drawText(text, start, end, x, y, paint);
+ canvas.drawText(text, start, end, x, y, paint,false);
}
if (fmi != null) {
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 8eae111..c05a8fe 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -32,7 +32,7 @@ public class Time {
private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000";
private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z";
private static final String Y_M_D = "%Y-%m-%d";
-
+
public static final String TIMEZONE_UTC = "UTC";
/**
@@ -170,11 +170,11 @@ public class Time {
public Time() {
this(TimeZone.getDefault().getID());
}
-
+
/**
* A copy constructor. Construct a Time object by copying the given
* Time object. No normalization occurs.
- *
+ *
* @param other
*/
public Time(Time other) {
@@ -185,17 +185,17 @@ public class Time {
* Ensures the values in each field are in range. For example if the
* current value of this calendar is March 32, normalize() will convert it
* to April 1. It also fills in weekDay, yearDay, isDst and gmtoff.
- *
+ *
* <p>
* If "ignoreDst" is true, then this method sets the "isDst" field to -1
* (the "unknown" value) before normalizing. It then computes the
* correct value for "isDst".
- *
+ *
* <p>
* See {@link #toMillis(boolean)} for more information about when to
* use <tt>true</tt> or <tt>false</tt> for "ignoreDst".
- *
- * @return the UTC milliseconds since the epoch
+ *
+ * @return the UTC milliseconds since the epoch
*/
native public long normalize(boolean ignoreDst);
@@ -379,13 +379,13 @@ public class Time {
* Parses a date-time string in either the RFC 2445 format or an abbreviated
* format that does not include the "time" field. For example, all of the
* following strings are valid:
- *
+ *
* <ul>
* <li>"20081013T160000Z"</li>
* <li>"20081013T160000"</li>
* <li>"20081013"</li>
* </ul>
- *
+ *
* Returns whether or not the time is in UTC (ends with Z). If the string
* ends with "Z" then the timezone is set to UTC. If the date-time string
* included only a date and no time field, then the <code>allDay</code>
@@ -396,10 +396,10 @@ public class Time {
* <code>yearDay</code>, and <code>gmtoff</code> are always set to zero,
* and the field <code>isDst</code> is set to -1 (unknown). To set those
* fields, call {@link #normalize(boolean)} after parsing.
- *
+ *
* To parse a date-time string and convert it to UTC milliseconds, do
* something like this:
- *
+ *
* <pre>
* Time time = new Time();
* String date = "20081013T160000Z";
@@ -428,25 +428,25 @@ public class Time {
* Parse a time in RFC 3339 format. This method also parses simple dates
* (that is, strings that contain no time or time offset). For example,
* all of the following strings are valid:
- *
+ *
* <ul>
* <li>"2008-10-13T16:00:00.000Z"</li>
* <li>"2008-10-13T16:00:00.000+07:00"</li>
* <li>"2008-10-13T16:00:00.000-07:00"</li>
* <li>"2008-10-13"</li>
* </ul>
- *
+ *
* <p>
* If the string contains a time and time offset, then the time offset will
* be used to convert the time value to UTC.
* </p>
- *
+ *
* <p>
* If the given string contains just a date (with no time field), then
* the {@link #allDay} field is set to true and the {@link #hour},
* {@link #minute}, and {@link #second} fields are set to zero.
* </p>
- *
+ *
* <p>
* Returns true if the resulting time value is in UTC time.
* </p>
@@ -462,7 +462,7 @@ public class Time {
}
return false;
}
-
+
native private boolean nativeParse3339(String s);
/**
@@ -484,13 +484,13 @@ public class Time {
* <em>not</em> change any of the fields in this Time object. If you want
* to normalize the fields in this Time object and also get the milliseconds
* then use {@link #normalize(boolean)}.
- *
+ *
* <p>
* If "ignoreDst" is false, then this method uses the current setting of the
* "isDst" field and will adjust the returned time if the "isDst" field is
* wrong for the given time. See the sample code below for an example of
* this.
- *
+ *
* <p>
* If "ignoreDst" is true, then this method ignores the current setting of
* the "isDst" field in this Time object and will instead figure out the
@@ -499,27 +499,27 @@ public class Time {
* correct value of the "isDst" field is when the time is inherently
* ambiguous because it falls in the hour that is repeated when switching
* from Daylight-Saving Time to Standard Time.
- *
+ *
* <p>
* Here is an example where <tt>toMillis(true)</tt> adjusts the time,
* assuming that DST changes at 2am on Sunday, Nov 4, 2007.
- *
+ *
* <pre>
* Time time = new Time();
- * time.set(2007, 10, 4); // set the date to Nov 4, 2007, 12am
+ * time.set(4, 10, 2007); // set the date to Nov 4, 2007, 12am
* time.normalize(); // this sets isDst = 1
* time.monthDay += 1; // changes the date to Nov 5, 2007, 12am
* millis = time.toMillis(false); // millis is Nov 4, 2007, 11pm
* millis = time.toMillis(true); // millis is Nov 5, 2007, 12am
* </pre>
- *
+ *
* <p>
* To avoid this problem, use <tt>toMillis(true)</tt>
* after adding or subtracting days or explicitly setting the "monthDay"
* field. On the other hand, if you are adding
* or subtracting hours or minutes, then you should use
* <tt>toMillis(false)</tt>.
- *
+ *
* <p>
* You should also use <tt>toMillis(false)</tt> if you want
* to read back the same milliseconds that you set with {@link #set(long)}
@@ -531,14 +531,14 @@ public class Time {
* Sets the fields in this Time object given the UTC milliseconds. After
* this method returns, all the fields are normalized.
* This also sets the "isDst" field to the correct value.
- *
+ *
* @param millis the time in UTC milliseconds since the epoch.
*/
native public void set(long millis);
/**
* Format according to RFC 2445 DATETIME type.
- *
+ *
* <p>
* The same as format("%Y%m%dT%H%M%S").
*/
@@ -584,7 +584,7 @@ public class Time {
* Sets the date from the given fields. Also sets allDay to true.
* Sets weekDay, yearDay and gmtoff to 0, and isDst to -1.
* Call {@link #normalize(boolean)} if you need those.
- *
+ *
* @param monthDay the day of the month (in the range [1,31])
* @param month the zero-based month number (in the range [0,11])
* @param year the year
@@ -606,7 +606,7 @@ public class Time {
/**
* Returns true if the time represented by this Time object occurs before
* the given time.
- *
+ *
* @param that a given Time object to compare against
* @return true if this time is less than the given time
*/
@@ -618,7 +618,7 @@ public class Time {
/**
* Returns true if the time represented by this Time object occurs after
* the given time.
- *
+ *
* @param that a given Time object to compare against
* @return true if this time is greater than the given time
*/
@@ -632,12 +632,12 @@ public class Time {
* closest Thursday yearDay.
*/
private static final int[] sThursdayOffset = { -3, 3, 2, 1, 0, -1, -2 };
-
+
/**
* Computes the week number according to ISO 8601. The current Time
* object must already be normalized because this method uses the
* yearDay and weekDay fields.
- *
+ *
* <p>
* In IS0 8601, weeks start on Monday.
* The first week of the year (week 1) is defined by ISO 8601 as the
@@ -645,12 +645,12 @@ public class Time {
* Or equivalently, the week containing January 4. Or equivalently,
* the week with the year's first Thursday in it.
* </p>
- *
+ *
* <p>
* The week number can be calculated by counting Thursdays. Week N
* contains the Nth Thursday of the year.
* </p>
- *
+ *
* @return the ISO week number.
*/
public int getWeekNumber() {
@@ -661,7 +661,7 @@ public class Time {
if (closestThursday >= 0 && closestThursday <= 364) {
return closestThursday / 7 + 1;
}
-
+
// The week crosses a year boundary.
Time temp = new Time(this);
temp.monthDay += sThursdayOffset[weekDay];
@@ -670,7 +670,7 @@ public class Time {
}
/**
- * Return a string in the RFC 3339 format.
+ * Return a string in the RFC 3339 format.
* <p>
* If allDay is true, expresses the time as Y-M-D</p>
* <p>
@@ -691,13 +691,13 @@ public class Time {
int offset = (int)Math.abs(gmtoff);
int minutes = (offset % 3600) / 60;
int hours = offset / 3600;
-
+
return String.format("%s%s%02d:%02d", base, sign, hours, minutes);
}
}
-
+
/**
- * Returns true if the day of the given time is the epoch on the Julian Calendar
+ * Returns true if the day of the given time is the epoch on the Julian Calendar
* (January 1, 1970 on the Gregorian calendar).
*
* @param time the time to test
@@ -707,7 +707,7 @@ public class Time {
long millis = time.toMillis(true);
return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY;
}
-
+
/**
* Computes the Julian day number, given the UTC milliseconds
* and the offset (in seconds) from UTC. The Julian day for a given
@@ -716,10 +716,10 @@ public class Time {
* what timezone is being used. The Julian day is useful for testing
* if two events occur on the same day and for determining the relative
* time of an event from the present ("yesterday", "3 days ago", etc.).
- *
+ *
* <p>
* Use {@link #toMillis(boolean)} to get the milliseconds.
- *
+ *
* @param millis the time in UTC milliseconds
* @param gmtoff the offset from UTC in seconds
* @return the Julian day
@@ -729,7 +729,7 @@ public class Time {
long julianDay = (millis + offsetMillis) / DateUtils.DAY_IN_MILLIS;
return (int) julianDay + EPOCH_JULIAN_DAY;
}
-
+
/**
* <p>Sets the time from the given Julian day number, which must be based on
* the same timezone that is set in this Time object. The "gmtoff" field
@@ -738,7 +738,7 @@ public class Time {
* After this method returns all the fields will be normalized and the time
* will be set to 12am at the beginning of the given Julian day.
* </p>
- *
+ *
* <p>
* The only exception to this is if 12am does not exist for that day because
* of daylight saving time. For example, Cairo, Eqypt moves time ahead one
@@ -746,7 +746,7 @@ public class Time {
* also change daylight saving time at 12am. In those cases, the time
* will be set to 1am.
* </p>
- *
+ *
* @param julianDay the Julian day in the timezone for this Time object
* @return the UTC milliseconds for the beginning of the Julian day
*/
@@ -756,13 +756,13 @@ public class Time {
// the day.
long millis = (julianDay - EPOCH_JULIAN_DAY) * DateUtils.DAY_IN_MILLIS;
set(millis);
-
+
// Figure out how close we are to the requested Julian day.
// We can't be off by more than a day.
int approximateDay = getJulianDay(millis, gmtoff);
int diff = julianDay - approximateDay;
monthDay += diff;
-
+
// Set the time to 12am and re-normalize.
hour = 0;
minute = 0;
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 8f40260..e21689d 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -36,6 +36,12 @@ public class HapticFeedbackConstants {
public static final int VIRTUAL_KEY = 1;
/**
+ * User has released a virtual on-screen key.
+ * @hide
+ */
+ public static final int VIRTUAL_RELEASED = 2;
+
+ /**
* The user has pressed a soft keyboard key.
*/
public static final int KEYBOARD_TAP = 3;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index d4f9787..2c78f2c 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -120,6 +120,15 @@ public class KeyEvent implements Parcelable {
public static final int KEYCODE_MEDIA_REWIND = 89;
public static final int KEYCODE_MEDIA_FAST_FORWARD = 90;
public static final int KEYCODE_MUTE = 91;
+ public static final int KEYCODE_FUNC_1 = 92;
+ public static final int KEYCODE_FUNC_2 = 93;
+ public static final int KEYCODE_FUNC_3 = 94;
+ public static final int KEYCODE_FUNC_4 = 95;
+ public static final int KEYCODE_FUNC_5 = 96;
+ public static final int KEYCODE_FUNC_6 = 97;
+ public static final int KEYCODE_FUNC_7 = 98;
+ public static final int KEYCODE_FUNC_8 = 99;
+ public static final int KEYCODE_QUECHAR = 100;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -135,7 +144,7 @@ public class KeyEvent implements Parcelable {
// those new codes. This is intended to maintain a consistent
// set of key code definitions across all Android devices.
- private static final int LAST_KEYCODE = KEYCODE_MUTE;
+ private static final int LAST_KEYCODE = KEYCODE_QUECHAR;
/**
* @deprecated There are now more than MAX_KEYCODE keycodes.
diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java
index 3bbfea8..a4475a1 100644
--- a/core/java/android/view/RawInputEvent.java
+++ b/core/java/android/view/RawInputEvent.java
@@ -28,6 +28,7 @@ public class RawInputEvent {
public static final int CLASS_TRACKBALL = 0x00000008;
public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
public static final int CLASS_DPAD = 0x00000020;
+ public static final int CLASS_MOUSE= 0x00000040;
// More special classes for QueuedEvent below.
public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 03efea9..2591a04 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -2586,6 +2586,9 @@ public final class ViewRoot extends Handler implements ViewParent,
switch (effectId) {
case SoundEffectConstants.CLICK:
audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
+ if (audioManager.queryHapticsAllEnabled()){
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_RELEASED, false);
+ };
return;
case SoundEffectConstants.NAVIGATION_DOWN:
audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 25df1f4..0d6f973 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -16,11 +16,15 @@
package android.view;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.os.Handler;
+import android.provider.Settings;
import android.util.Config;
import android.util.Log;
@@ -39,6 +43,10 @@ public abstract class WindowOrientationListener {
private int mRate;
private Sensor mSensor;
private SensorEventListenerImpl mSensorEventListener;
+ private Context mContext;
+ private Handler mHandler;
+ private SettingsObserver mSettingsObserver;
+ private int mAccelerometerMode;
/**
* Creates a new WindowOrientationListener.
@@ -70,6 +78,8 @@ public abstract class WindowOrientationListener {
// Create listener only if sensors do exist
mSensorEventListener = new SensorEventListenerImpl();
}
+ mContext = context;
+ mHandler = new Handler();
}
/**
@@ -85,6 +95,10 @@ public abstract class WindowOrientationListener {
if (localLOGV) Log.d(TAG, "WindowOrientationListener enabled");
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
mEnabled = true;
+ if (mSettingsObserver == null) {
+ mSettingsObserver = new SettingsObserver(mHandler);
+ }
+ mSettingsObserver.observe();
}
}
@@ -100,6 +114,10 @@ public abstract class WindowOrientationListener {
if (localLOGV) Log.d(TAG, "WindowOrientationListener disabled");
mSensorManager.unregisterListener(mSensorEventListener);
mEnabled = false;
+ if (mSettingsObserver != null) {
+ mSettingsObserver.stop();
+ mSettingsObserver = null;
+ }
}
}
@@ -110,6 +128,38 @@ public abstract class WindowOrientationListener {
return -1;
}
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.ACCELEROMETER_ROTATION_MODE), false, this);
+ if (localLOGV) Log.i(TAG, "SettingsObserver enabled");
+ update();
+ }
+
+ public void stop() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ if (localLOGV) Log.i(TAG, "SettingsObserver disabled");
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ update();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mAccelerometerMode = Settings.System.getInt(resolver,
+ Settings.System.ACCELEROMETER_ROTATION_MODE, 5);
+ if (localLOGV) Log.i(TAG, "mAccelerometerMode=" + mAccelerometerMode);
+ }
+ }
+
class SensorEventListenerImpl implements SensorEventListener {
// We work with all angles in degrees in this class.
private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
@@ -123,14 +173,15 @@ public abstract class WindowOrientationListener {
// ROTATION_90 = right side of device facing the sky, etc.
private static final int ROTATION_0 = 0;
private static final int ROTATION_90 = 1;
- private static final int ROTATION_270 = 2;
+ private static final int ROTATION_180 = 2;
+ private static final int ROTATION_270 = 3;
// Current orientation state
private int mRotation = ROTATION_0;
// Mapping our internal aliases into actual Surface rotation values
private final int[] SURFACE_ROTATIONS = new int[] {Surface.ROTATION_0, Surface.ROTATION_90,
- Surface.ROTATION_270};
+ Surface.ROTATION_180, Surface.ROTATION_270};
// Threshold ranges of orientation angle to transition into other orientation states.
// The first list is for transitions from ROTATION_0, the next for ROTATION_90, etc.
@@ -140,16 +191,18 @@ public abstract class WindowOrientationListener {
// between two states with a swing of 30 degrees for hysteresis. For ROTATION_180,
// however, we enforce stricter thresholds, pushing the thresholds 15 degrees closer to 180.
private final int[][][] THRESHOLDS = new int[][][] {
- {{60, 180}, {180, 300}},
- {{0, 45}, {45, 165}, {330, 360}},
- {{0, 30}, {195, 315}, {315, 360}}
+ {{60, 165}, {165, 195}, {195, 300}},
+ {{0, 30}, {150, 210}, {30, 150}, {330, 360}},
+ {{240, 345}, {15, 120}, {0, 15}, {345, 360}},
+ {{0, 30}, {150, 195}, {195, 315}, {315, 360}}
};
// See THRESHOLDS
private final int[][] ROTATE_TO = new int[][] {
- {ROTATION_270, ROTATION_90},
- {ROTATION_0, ROTATION_270, ROTATION_0},
- {ROTATION_0, ROTATION_90, ROTATION_0}
+ {ROTATION_270, ROTATION_180, ROTATION_90},
+ {ROTATION_0, ROTATION_180, ROTATION_270, ROTATION_0},
+ {ROTATION_90, ROTATION_270, ROTATION_0, ROTATION_0},
+ {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0}
};
// Maximum absolute tilt angle at which to consider orientation changes. Beyond this (i.e.
@@ -159,7 +212,7 @@ public abstract class WindowOrientationListener {
// Additional limits on tilt angle to transition to each new orientation. We ignore all
// vectors with tilt beyond MAX_TILT, but we can set stricter limits on transition to a
// particular orientation here.
- private final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, MAX_TILT, MAX_TILT};
+ private final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, MAX_TILT, MAX_TILT, MAX_TILT};
// Between this tilt angle and MAX_TILT, we'll allow orientation changes, but we'll filter
// with a higher time constant, making us less sensitive to change. This primarily helps
@@ -224,6 +277,25 @@ public abstract class WindowOrientationListener {
return;
}
+ boolean allowed = rotation == ROTATION_0;
+ if (!allowed) {
+ switch (rotation) {
+ case ROTATION_90:
+ allowed = (mAccelerometerMode & 1) != 0;
+ break;
+ case ROTATION_180:
+ allowed = (mAccelerometerMode & 2) != 0;
+ break;
+ case ROTATION_270:
+ allowed = (mAccelerometerMode & 4) != 0;
+ break;
+ }
+ }
+ if (!allowed) {
+ if (localLOGV) Log.i(TAG, " not allowed rotation = " + rotation);
+ return;
+ }
+
if (localLOGV) Log.i(TAG, " new rotation = " + rotation);
mRotation = rotation;
onOrientationChanged(SURFACE_ROTATIONS[rotation]);
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 219a469..ec0858c 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -229,6 +230,22 @@ class BrowserFrame extends Handler {
}
}
+ public void startDnsPrefetch() {
+ if (DebugFlags.BROWSER_FRAME) {
+ Log.v(LOGTAG, "Starting DNS prefetch");
+ }
+
+ DnsResolver dnsResolver = DnsResolver.getInstance();
+ if(dnsResolver == null )
+ return;
+
+ HashMap hostsMap = nativeGetEmbeddedHostNames(dnsResolver.getMaxParallelDnsQueryPerPage());
+ if(hostsMap == null)
+ return;
+
+ dnsResolver.resolveDnsForHostMap(hostsMap);
+ }
+
/**
* Load a url from the network or the filesystem into the main frame.
* Following the same behaviour as Safari, javascript: URLs are not passed
@@ -643,7 +660,9 @@ class BrowserFrame extends Handler {
boolean userGesture,
boolean synchronous,
String username,
- String password) {
+ String password,
+ int priority,
+ boolean commit) {
PerfChecker checker = new PerfChecker();
if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
@@ -717,6 +736,8 @@ class BrowserFrame extends Handler {
LoadListener loadListener = LoadListener.getLoadListener(mContext,
this, url, loaderHandle, synchronous, isMainFramePage,
mainResource, userGesture, postDataIdentifier, username, password);
+ loadListener.setPriority(priority);
+ loadListener.setShouldCommit(commit);
mCallbackProxy.onLoadResource(url);
@@ -967,6 +988,8 @@ class BrowserFrame extends Handler {
private native void nativeLoadData(String baseUrl, String data,
String mimeType, String encoding, String historyUrl);
+ private native HashMap nativeGetEmbeddedHostNames(int maxDnsHostCount);
+
/**
* Stop loading the current page.
*/
diff --git a/core/java/android/webkit/DnsResolver.java b/core/java/android/webkit/DnsResolver.java
new file mode 100644
index 0000000..80a0808
--- /dev/null
+++ b/core/java/android/webkit/DnsResolver.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.webkit;
+
+import android.os.Handler;
+import android.util.Log;
+import android.os.Message;
+import android.os.Process;
+
+import java.lang.Thread;
+import java.lang.InterruptedException;
+import java.net.UnknownHostException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+final class DnsResolver {
+
+ private static final String LOGTAG = "webcore";
+
+ /* Max Thread pool size is taken from data published by google
+ * that mentions max hosts per webpage = 8 */
+ private final int MAX_DNS_RESOLVER_THREAD_POOL_SIZE = 8;
+
+ /* This number is derived by considering various factors such as OS DNS cache size,
+ * Browser Cache size and realistic need to spent time on DNS prefetch
+ */
+ private final int MAX_PARALLEL_DNS_QUERIES_PER_PAGE = 64;
+
+ private volatile boolean mDnsResolverThreadPoolRunning = false;
+
+ private volatile boolean mShutDownInProgress = false;
+
+ private static DnsResolver sDnsResolver;
+
+ private HashMap mHostNamesToBeResolved;
+
+ private ExecutorService mDnsResolverThreadPool;
+
+ private static int mDnsResolverRefCount = 0;
+
+ /* Lock to synchronize the access to threadpool */
+ private static Object mThreadPoolLock = new Object();
+
+ public static synchronized DnsResolver createDnsResolver() {
+ if (sDnsResolver == null) {
+ sDnsResolver = new DnsResolver();
+ }
+ ++mDnsResolverRefCount;
+ return sDnsResolver;
+ }
+
+ public static DnsResolver getInstance() {
+ return sDnsResolver;
+ }
+
+ private DnsResolver() {
+ createDnsResolverThreadPool();
+ }
+
+ private void createDnsResolverThreadPool() {
+ final Runnable startDnsResolver = new Runnable() {
+ public void run() {
+ /* DNS resolver priority should be same as of HTTP thread pool */
+ Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DEFAULT +
+ android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
+ mDnsResolverThreadPool = Executors.newFixedThreadPool(MAX_DNS_RESOLVER_THREAD_POOL_SIZE);
+ mHostNamesToBeResolved = new HashMap();
+ boolean bResolvedPriorityHostNames = false;
+ int dnsQueryCounter = 0;
+ int numHosts = 0;
+ while(!mShutDownInProgress) {
+ synchronized(mHostNamesToBeResolved) {
+ numHosts = mHostNamesToBeResolved.size();
+ }
+ if(numHosts <= 0) {
+ try {
+ dnsQueryCounter = 0;
+ bResolvedPriorityHostNames = false;
+ mDnsResolverThreadPoolRunning = true;
+ synchronized(mThreadPoolLock) {
+ mThreadPoolLock.wait();
+ }
+ } catch(java.lang.InterruptedException e) {
+ }
+ }
+ else {
+ synchronized(mHostNamesToBeResolved) {
+ Iterator iterator = mHostNamesToBeResolved.entrySet().iterator();
+ while(iterator.hasNext() && mDnsResolverThreadPoolRunning && (dnsQueryCounter < MAX_PARALLEL_DNS_QUERIES_PER_PAGE)) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ final String hostName = (String)entry.getKey();
+ final String priority = (String)entry.getValue();
+ if( (!bResolvedPriorityHostNames && priority.equalsIgnoreCase("1")) ||
+ ( bResolvedPriorityHostNames && priority.equalsIgnoreCase("0"))
+ ) {
+ ++dnsQueryCounter;
+ iterator.remove();
+ Runnable task = new Runnable() {
+ public void run() {
+ try {
+ java.net.InetAddress.getByName(hostName);
+ } catch(java.net.UnknownHostException e) {
+ }
+ }
+ };
+ mDnsResolverThreadPool.execute (task);
+ }
+ }
+ if(!mDnsResolverThreadPoolRunning || (dnsQueryCounter >= MAX_PARALLEL_DNS_QUERIES_PER_PAGE)) {
+ mHostNamesToBeResolved.clear();
+ }
+ bResolvedPriorityHostNames = (bResolvedPriorityHostNames) ? false:true;
+ }
+ }
+ }
+ mDnsResolverThreadPool.shutdown();
+ sDnsResolver = null;
+ }
+ };
+ Thread dnsResolver = new Thread(startDnsResolver);
+ dnsResolver.setName("DNS resolver");
+ dnsResolver.start();
+ }
+
+ public synchronized void destroyDnsResolver() {
+ --mDnsResolverRefCount;
+ if(mDnsResolverRefCount == 0) {
+ mShutDownInProgress = true;
+ mDnsResolverThreadPoolRunning = false;
+ synchronized(mThreadPoolLock) {
+ mThreadPoolLock.notifyAll();
+ }
+ }
+ }
+
+ public void resolveDnsForHost(String hostName, String priority) {
+ if(hostName == null) {
+ return;
+ }
+ synchronized(mHostNamesToBeResolved) {
+ if(mHostNamesToBeResolved.size() > 0 ) {
+ return;
+ }
+ mHostNamesToBeResolved.put(hostName,priority);
+ }
+ resumeDnsResolverThreadPool();
+ }
+
+ public void resolveDnsForHostMap(HashMap hostMap) {
+ if(hostMap == null) {
+ return;
+ }
+ synchronized (mHostNamesToBeResolved) {
+ mHostNamesToBeResolved.putAll(hostMap);
+ }
+ resumeDnsResolverThreadPool();
+ }
+
+ /* pause will flush all pending DNS queries at the DNS resolver */
+ public void pauseDnsResolverThreadPool() {
+ mDnsResolverThreadPoolRunning = false;
+ }
+
+ /* resume will start DNS resolver executing DNS queries */
+ public void resumeDnsResolverThreadPool() {
+ mDnsResolverThreadPoolRunning = true;
+ synchronized(mThreadPoolLock) {
+ mThreadPoolLock.notifyAll();
+ }
+ }
+
+ /* returns the max number of DNS queries that can be made in background for a page */
+ public int getMaxParallelDnsQueryPerPage() {
+ return MAX_PARALLEL_DNS_QUERIES_PER_PAGE;
+ }
+}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index eda2e72..20b987c 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -345,7 +345,7 @@ class HTML5VideoViewProxy extends Handler
// Start the download. Called on WebCore thread.
public void start() {
retainQueue();
- mRequestHandle = mRequestQueue.queueRequest(mUrl, "GET", null, this, null, 0);
+ mRequestHandle = mRequestQueue.queueRequest(mUrl, "GET", null, this, null, 0, -1, false);
}
// Cancel the download if active and release the queue. Called on WebCore thread.
public void cancelAndReleaseQueue() {
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index e6fa405..3cdd86b 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -131,6 +131,9 @@ class LoadListener extends Handler implements EventHandler {
private final String mUsername;
private final String mPassword;
+ private int mPriority = -1;
+ private boolean mCommit = true;
+
// =========================================================================
// Public functions
// =========================================================================
@@ -183,6 +186,22 @@ class LoadListener extends Handler implements EventHandler {
mNativeLoader = 0;
}
+ public void setPriority(int pri) {
+ mPriority = pri;
+ }
+
+ public int priority() {
+ return mPriority;
+ }
+
+ public void setShouldCommit(boolean commit) {
+ mCommit = commit;
+ }
+
+ public boolean shouldCommit() {
+ return mCommit;
+ }
+
/*
* This message handler is to facilitate communication between the network
* thread and the browser thread.
@@ -1242,6 +1261,24 @@ class LoadListener extends Handler implements EventHandler {
}
/**
+ * native callback
+ * Propagates the priority to the network stack
+ */
+ void setPriority(String url, int pri) {
+ Network net = Network.getInstance(mContext);
+ net.setPriority(url, pri);
+ }
+
+ /**
+ * native callback
+ * Commits the priorities set on the network stack
+ */
+ void commitPriorities() {
+ Network net = Network.getInstance(mContext);
+ net.commitPriorities();
+ }
+
+ /**
* Cancel a request.
* FIXME: This will only work if the request has yet to be handled. This
* is in no way guarenteed if requests are served in a separate thread.
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 598f20d..accbebb 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -17,6 +17,8 @@
package android.webkit;
import android.content.Context;
+import android.net.WebAddress;
+import android.net.ParseException;
import android.net.http.*;
import android.os.*;
import android.util.Log;
@@ -142,6 +144,25 @@ class Network {
mRequestQueue = new RequestQueue(context);
}
+ public boolean setPriority(String url, int priority) {
+ WebAddress uri = null;
+ if (URLUtil.isNetworkUrl(url)) {
+ String nurl = URLUtil.stripAnchor(url);
+ try {
+ uri = new WebAddress(nurl);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ if (uri != null)
+ return mRequestQueue.setRequestPriority(uri, priority);
+ return false;
+ }
+
+ public void commitPriorities() {
+ mRequestQueue.commitRequestPriorities();
+ }
+
/**
* Request a url from either the network or the file system.
* @param url The url to load.
@@ -189,7 +210,8 @@ class Network {
loader.loadSynchronousMessages();
} else {
handle = q.queueRequest(url, loader.getWebAddress(), method,
- headers, loader, bodyProvider, bodyLength);
+ headers, loader, bodyProvider, bodyLength,
+ loader.priority(), loader.shouldCommit());
// FIXME: Although this is probably a rare condition, normal network
// requests are processed in a separate thread. This means that it
// is possible to process part of the request before setting the
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index b767f11..cfb6b92 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -424,6 +424,14 @@ public class WebSettings {
public boolean getNavDump() {
return mNavDump;
}
+
+ /**
+ * Whether or not to display zoom controls
+ * @hide
+ */
+ public void showZoomControls(boolean value) {
+ mWebView.showZoomControls(value);
+ }
/**
* Set whether the WebView supports zoom
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2df250d..f3ddbb6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,6 +47,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.provider.Settings;
import android.text.IClipboard;
import android.text.Selection;
import android.text.Spannable;
@@ -774,6 +776,9 @@ public class WebView extends AbsoluteLayout
public static final String SCHEME_GEO = "geo:0,0?q=";
private int mBackgroundColor = Color.WHITE;
+
+ //Wysie
+ private boolean showZoomControls = true;
// Used to notify listeners of a new picture.
private PictureListener mPictureListener;
@@ -945,6 +950,11 @@ public class WebView extends AbsoluteLayout
updateMultiTouchSupport(context);
}
+
+ //Wysie
+ void showZoomControls(boolean value) {
+ showZoomControls = value;
+ }
void updateMultiTouchSupport(Context context) {
WebSettings settings = getSettings();
@@ -961,17 +971,21 @@ public class WebView extends AbsoluteLayout
private void updateZoomButtonsEnabled() {
if (mZoomButtonsController == null) return;
- boolean canZoomIn = mActualScale < mMaxZoomScale;
- boolean canZoomOut = mActualScale > mMinZoomScale && !mInZoomOverview;
- if (!canZoomIn && !canZoomOut) {
- // Hide the zoom in and out buttons, as well as the fit to page
- // button, if the page cannot zoom
+ if (!showZoomControls) {
mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
} else {
- // Set each one individually, as a page may be able to zoom in
- // or out.
- mZoomButtonsController.setZoomInEnabled(canZoomIn);
- mZoomButtonsController.setZoomOutEnabled(canZoomOut);
+ boolean canZoomIn = mActualScale < mMaxZoomScale;
+ boolean canZoomOut = mActualScale > mMinZoomScale && !mInZoomOverview;
+ if (!canZoomIn && !canZoomOut) {
+ // Hide the zoom in and out buttons, as well as the fit to page
+ // button, if the page cannot zoom
+ mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
+ } else {
+ // Set each one individually, as a page may be able to zoom in
+ // or out.
+ mZoomButtonsController.setZoomInEnabled(canZoomIn);
+ mZoomButtonsController.setZoomOutEnabled(canZoomOut);
+ }
}
}
@@ -1285,6 +1299,13 @@ public class WebView extends AbsoluteLayout
}
/**
+ * @hide pending API council approval.
+ */
+ public void startDnsPrefetch() {
+ mWebViewCore.sendMessage(EventHub.START_DNS_PREFETCH);
+ }
+
+ /**
* Inform WebView of the network state. This is used to set
* the javascript property window.navigator.isOnline and
* generates the online/offline event as specified in HTML5, sec. 5.7.7
@@ -4601,6 +4622,10 @@ public class WebView extends AbsoluteLayout
boolean reflowNow = (mActualScale - mMinZoomScale
<= MINIMUM_SCALE_INCREMENT)
|| ((mActualScale <= 0.8 * mTextWrapScale));
+ if(mActualScale > mTextWrapScale) {
+ reflowNow |= Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.WEB_VIEW_PINCH_REFLOW, 0) != 0;
+ }
// force zoom after mPreviewZoomOnly is set to false so that the
// new view size will be passed to the WebKit
setNewZoomScale(mActualScale, reflowNow, true);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4118119..68c0fb8 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -197,6 +198,8 @@ final class WebViewCore {
// WebCore thread handler.
mEventHub.transferMessages();
+ DnsResolver.createDnsResolver();
+
// Send a message back to WebView to tell it that we have set up the
// WebCore thread.
if (mWebView != null) {
@@ -771,6 +774,7 @@ final class WebViewCore {
"ON_RESUME", // = 144
"FREE_MEMORY", // = 145
"VALID_NODE_BOUNDS", // = 146
+ "START_DNS_PREFETCH", // = 151
};
class EventHub {
@@ -839,6 +843,7 @@ final class WebViewCore {
// Network-based messaging
static final int CLEAR_SSL_PREF_TABLE = 150;
+ static final int START_DNS_PREFETCH = 151;
// Test harness messages
static final int REQUEST_EXT_REPRESENTATION = 160;
@@ -944,6 +949,7 @@ final class WebViewCore {
break;
case LOAD_URL: {
+ DnsResolver.getInstance().pauseDnsResolverThreadPool();
GetUrlData param = (GetUrlData) msg.obj;
loadUrl(param.mUrl, param.mExtraHeaders);
break;
@@ -1000,6 +1006,7 @@ final class WebViewCore {
break;
case RELOAD:
+ DnsResolver.getInstance().pauseDnsResolverThreadPool();
mBrowserFrame.reload(false);
break;
@@ -1043,6 +1050,7 @@ final class WebViewCore {
if (!mBrowserFrame.committed() && msg.arg1 == -1 &&
(mBrowserFrame.loadType() ==
BrowserFrame.FRAME_LOADTYPE_STANDARD)) {
+ DnsResolver.getInstance().pauseDnsResolverThreadPool();
mBrowserFrame.reload(true);
} else {
mBrowserFrame.goBackOrForward(msg.arg1);
@@ -1357,6 +1365,10 @@ final class WebViewCore {
BrowserFrame.sJavaBridge.removePackageName(
(String) msg.obj);
break;
+
+ case START_DNS_PREFETCH:
+ mBrowserFrame.startDnsPrefetch();
+ break;
}
}
};
@@ -1544,6 +1556,10 @@ final class WebViewCore {
}
mEventHub.blockMessages();
}
+
+ DnsResolver r = DnsResolver.getInstance();
+ if (r != null)
+ r.destroyDnsResolver();
}
//-------------------------------------------------------------------------
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 02cd6a8..e0f1583 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -51,6 +51,14 @@ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchMode
* {@hide}
*/
protected int mCurrentTab = -1;
+ /**
+ * This field when set to true ensures that first tab is not set as the current tab
+ * by preventing the addTab() from calling setCurrentTab() with index set to 0.
+ * To ensure that the operations of an application are not changed, it should be set to
+ * false whenever mCurrenttab is set to -1.
+ * {@hide}
+ */
+ private boolean mAvoidFirstTabLoad = false;
private View mCurrentView = null;
/**
* This field should be made private, so it is hidden from the SDK.
@@ -75,6 +83,7 @@ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchMode
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
mCurrentTab = -1;
+ mAvoidFirstTabLoad = false;
mCurrentView = null;
}
@@ -209,7 +218,9 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
mTabWidget.addView(tabIndicator);
mTabSpecs.add(tabSpec);
- if (mCurrentTab == -1) {
+ // The second test is always true except when an application explicitly sets
+ // mAvoidFirstTabLoad to true.
+ if (mCurrentTab == -1 && !mAvoidFirstTabLoad) {
setCurrentTab(0);
}
}
@@ -252,7 +263,18 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
public View getCurrentView() {
return mCurrentView;
}
-
+ /**
+ * {@hide}
+ */
+ public void setAvoidFirstTabLoad(boolean flag) {
+ mAvoidFirstTabLoad = flag;
+ }
+ /**
+ * {@hide}
+ */
+ public void setCurrentTabToZero() {
+ mCurrentTab = 0;
+ }
public void setCurrentTabByTag(String tag) {
int i;
for (i = 0; i < mTabSpecs.size(); i++) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 64c9c99..2b37887 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2778,7 +2778,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void drawText(Canvas c, int start, int end,
float x, float y, Paint p) {
- c.drawText(mChars, start + mStart, end - start, x, y, p);
+ c.drawText(mChars, start + mStart, end - start, x, y, p,false);
}
public float measureText(int start, int end, Paint p) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 107b145..4a0617c 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -435,6 +435,7 @@ public class AlertController {
View titleTemplate = mWindow.findViewById(R.id.title_template);
titleTemplate.setVisibility(View.GONE);
mIconView.setVisibility(View.GONE);
+ topPanel.setVisibility(View.GONE);
hasTitle = false;
}
}
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index a96253b..310ae99 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -94,17 +94,33 @@ public final class ShutdownThread extends Thread {
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();
+ final AlertDialog dialog;
+ // Set different dialog message based on whether or not we're rebooting
+ if (mReboot) {
+ dialog = new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(com.android.internal.R.string.reboot_system)
+ .setMessage(com.android.internal.R.string.reboot_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();
+ } else {
+ 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);
if (!context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
@@ -139,8 +155,13 @@ public final class ShutdownThread extends Thread {
// 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));
+ if (mReboot) {
+ pd.setTitle(context.getText(com.android.internal.R.string.reboot_system));
+ pd.setMessage(context.getText(com.android.internal.R.string.reboot_progress));
+ } else {
+ 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);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index aadb576..55b25f6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -844,7 +844,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
- byte[] buffer = new byte[4096];
+ byte[] buffer = new byte[8192];
int len;
try {
@@ -891,9 +891,11 @@ public final class BatteryStatsImpl extends BatteryStats {
for (endIndex=startIndex;
endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
endIndex++);
- // Don't go over the end of the buffer
- if (endIndex < len) {
- endIndex++; // endIndex is an exclusive upper bound.
+ endIndex++; // endIndex is an exclusive upper bound.
+ // Don't go over the end of the buffer, Process.parseProcLine might
+ // write to wlBuffer[endIndex]
+ if (endIndex >= (len - 1) ) {
+ return m;
}
String[] nameStringArray = mProcWakelocksName;
@@ -1224,6 +1226,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mPhoneSignalStrengthBin != bin) {
if (mPhoneSignalStrengthBin >= 0) {
mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
+ } else {
+ mPhoneSignalStrengthsTimer[SIGNAL_STRENGTH_NONE_OR_UNKNOWN].stopRunningLocked(this);
}
mPhoneSignalStrengthBin = bin;
mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
index 5f5c7a4..127fb23 100644
--- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java
+++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
@@ -85,7 +85,8 @@ public class SamplingProfilerIntegration {
pending = true;
snapshotWriter.execute(new Runnable() {
public void run() {
- String dir = "/sdcard/snapshots";
+ String dir =
+ Environment.getExternalStorageDirectory().getPath() + "/snapshots";
if (!dirMade) {
new File(dir).mkdirs();
if (new File(dir).isDirectory()) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index dbbd286..b227d67 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -90,7 +90,7 @@ public class LockPatternUtils {
private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
- private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
+ private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -572,6 +572,62 @@ public class LockPatternUtils {
public void setTactileFeedbackEnabled(boolean enabled) {
setBoolean(Settings.Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, enabled);
}
+
+ public void setVisibleDotsEnabled(boolean enabled) {
+ setBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, enabled);
+ }
+
+ public boolean isVisibleDotsEnabled() {
+ return getBoolean(Settings.Secure.LOCK_DOTS_VISIBLE, true);
+ }
+
+ public void setShowErrorPath(boolean enabled) {
+ setBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, enabled);
+ }
+
+ public boolean isShowErrorPath() {
+ return getBoolean(Settings.Secure.LOCK_SHOW_ERROR_PATH, true);
+ }
+
+ public void setShowCustomMsg(boolean enabled) {
+ setBoolean(Settings.Secure.LOCK_SHOW_CUSTOM_MSG, enabled);
+ }
+
+ public boolean isShowCustomMsg() {
+ return getBoolean(Settings.Secure.LOCK_SHOW_CUSTOM_MSG, false);
+ }
+
+ public void setCustomMsg(String msg) {
+ setString(Settings.Secure.LOCK_CUSTOM_MSG, msg);
+ }
+
+ public String getCustomMsg() {
+ return getString(Settings.Secure.LOCK_CUSTOM_MSG);
+ }
+
+ public int getIncorrectDelay() {
+ return getInt(Settings.Secure.LOCK_INCORRECT_DELAY, 2000);
+ }
+
+ public void setIncorrectDelay(int delay) {
+ setInt(Settings.Secure.LOCK_INCORRECT_DELAY, delay);
+ }
+
+ public void setShowUnlockMsg(boolean enabled) {
+ setBoolean(Settings.Secure.SHOW_UNLOCK_TEXT, enabled);
+ }
+
+ public boolean isShowUnlockMsg() {
+ return getBoolean(Settings.Secure.SHOW_UNLOCK_TEXT, true);
+ }
+
+ public void setShowUnlockErrMsg(boolean enabled) {
+ setBoolean(Settings.Secure.SHOW_UNLOCK_ERR_TEXT, enabled);
+ }
+
+ public boolean isShowUnlockErrMsg() {
+ return getBoolean(Settings.Secure.SHOW_UNLOCK_ERR_TEXT, true);
+ }
/**
* Set and store the lockout deadline, meaning the user can't attempt his/her unlock
@@ -636,6 +692,13 @@ public class LockPatternUtils {
return 1 ==
android.provider.Settings.Secure.getInt(mContentResolver, secureSettingKey, 0);
}
+
+ private boolean getBoolean(String systemSettingKey, boolean defaultValue) {
+ return 1 ==
+ android.provider.Settings.Secure.getInt(
+ mContentResolver,
+ systemSettingKey, defaultValue ? 1 : 0);
+ }
private void setBoolean(String secureSettingKey, boolean enabled) {
android.provider.Settings.Secure.putInt(mContentResolver, secureSettingKey,
@@ -649,6 +712,27 @@ public class LockPatternUtils {
private void setLong(String secureSettingKey, long value) {
android.provider.Settings.Secure.putLong(mContentResolver, secureSettingKey, value);
}
+
+ private int getInt(String systemSettingKey, int def) {
+ return android.provider.Settings.Secure.getInt(mContentResolver, systemSettingKey, def);
+ }
+
+ private void setInt(String systemSettingKey, int value) {
+ android.provider.Settings.Secure.putInt(mContentResolver, systemSettingKey, value);
+ }
+
+ private String getString(String systemSettingKey) {
+ String s = android.provider.Settings.Secure.getString(mContentResolver, systemSettingKey);
+
+ if (s == null)
+ return "";
+
+ return s;
+ }
+
+ private void setString(String systemSettingKey, String value) {
+ android.provider.Settings.Secure.putString(mContentResolver, systemSettingKey, value);
+ }
public boolean isSecure() {
long mode = getKeyguardStoredPasswordQuality();
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 007e7b9..8ae5a2f 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -101,6 +101,10 @@ public class LockPatternView extends View {
private boolean mInStealthMode = false;
private boolean mTactileFeedbackEnabled = true;
private boolean mPatternInProgress = false;
+
+ private boolean mVisibleDots = true;
+ private boolean mShowErrorPath = true;
+ private int mDelay = 2000;
private float mDiameterFactor = 0.5f;
private float mHitFactor = 0.6f;
@@ -332,6 +336,22 @@ public class LockPatternView extends View {
public void setInStealthMode(boolean inStealthMode) {
mInStealthMode = inStealthMode;
}
+
+ public void setVisibleDots(boolean visibleDots) {
+ mVisibleDots = visibleDots;
+ }
+
+ public boolean isVisibleDots() {
+ return mVisibleDots;
+ }
+
+ public void setShowErrorPath(boolean showErrorPath) {
+ mShowErrorPath = showErrorPath;
+ }
+
+ public boolean isShowErrorPath() {
+ return mShowErrorPath;
+ }
/**
* Set whether the view will use tactile feedback. If true, there will be
@@ -433,6 +453,14 @@ public class LockPatternView extends View {
public void enableInput() {
mInputEnabled = true;
}
+
+ public int getIncorrectDelay() {
+ return mDelay;
+ }
+
+ public void setIncorrectDelay(int delay) {
+ mDelay = delay;
+ }
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
@@ -838,7 +866,10 @@ public class LockPatternView extends View {
// only the last segment of the path should be computed here
// draw the path of the pattern (unless the user is in progress, and
// we are in stealth mode)
- final boolean drawPath = (!mInStealthMode || mPatternDisplayMode == DisplayMode.Wrong);
+ final boolean drawPath = ((!mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)
+ || (mPatternDisplayMode == DisplayMode.Wrong && mShowErrorPath));
+
+ //final boolean drawPath = (!mInStealthMode || mPatternDisplayMode == DisplayMode.Wrong);
if (drawPath) {
boolean anyCircles = false;
for (int i = 0; i < count; i++) {
@@ -872,13 +903,15 @@ public class LockPatternView extends View {
// draw the circles
final int paddingTop = mPaddingTop;
final int paddingLeft = mPaddingLeft;
-
- for (int i = 0; i < 3; i++) {
- float topY = paddingTop + i * squareHeight;
- //float centerY = mPaddingTop + i * mSquareHeight + (mSquareHeight / 2);
- for (int j = 0; j < 3; j++) {
- float leftX = paddingLeft + j * squareWidth;
- drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);
+
+ if (mVisibleDots) {
+ for (int i = 0; i < 3; i++) {
+ float topY = paddingTop + i * squareHeight;
+ //float centerY = mPaddingTop + i * mSquareHeight + (mSquareHeight / 2);
+ for (int j = 0; j < 3; j++) {
+ float leftX = paddingLeft + j * squareWidth;
+ drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);
+ }
}
}
@@ -959,8 +992,15 @@ public class LockPatternView extends View {
innerCircle = mBitmapBtnTouched;
} else if (mPatternDisplayMode == DisplayMode.Wrong) {
// the pattern is wrong
- outerCircle = mBitmapCircleRed;
- innerCircle = mBitmapBtnDefault;
+
+ if (mShowErrorPath) {
+ outerCircle = mBitmapCircleRed;
+ innerCircle = mBitmapBtnDefault;
+ }
+ else {
+ outerCircle = mBitmapCircleDefault;
+ innerCircle = mBitmapBtnDefault;
+ }
} else if (mPatternDisplayMode == DisplayMode.Correct ||
mPatternDisplayMode == DisplayMode.Animate) {
// the pattern is correct
@@ -989,7 +1029,7 @@ public class LockPatternView extends View {
return new SavedState(superState,
LockPatternUtils.patternToString(mPattern),
mPatternDisplayMode.ordinal(),
- mInputEnabled, mInStealthMode, mTactileFeedbackEnabled);
+ mInputEnabled, mInStealthMode, mTactileFeedbackEnabled, mVisibleDots, mShowErrorPath);
}
@Override
@@ -1003,6 +1043,8 @@ public class LockPatternView extends View {
mInputEnabled = ss.isInputEnabled();
mInStealthMode = ss.isInStealthMode();
mTactileFeedbackEnabled = ss.isTactileFeedbackEnabled();
+ mVisibleDots = ss.isVisibleDots();
+ mShowErrorPath = ss.isShowErrorPath();
}
/**
@@ -1015,18 +1057,22 @@ public class LockPatternView extends View {
private final boolean mInputEnabled;
private final boolean mInStealthMode;
private final boolean mTactileFeedbackEnabled;
+ private final boolean mVisibleDots;
+ private final boolean mShowErrorPath;
/**
* Constructor called from {@link LockPatternView#onSaveInstanceState()}
*/
private SavedState(Parcelable superState, String serializedPattern, int displayMode,
- boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {
+ boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled, boolean visibleDots, boolean showErrorPath) {
super(superState);
mSerializedPattern = serializedPattern;
mDisplayMode = displayMode;
mInputEnabled = inputEnabled;
mInStealthMode = inStealthMode;
mTactileFeedbackEnabled = tactileFeedbackEnabled;
+ mVisibleDots = visibleDots;
+ mShowErrorPath = showErrorPath;
}
/**
@@ -1039,6 +1085,8 @@ public class LockPatternView extends View {
mInputEnabled = (Boolean) in.readValue(null);
mInStealthMode = (Boolean) in.readValue(null);
mTactileFeedbackEnabled = (Boolean) in.readValue(null);
+ mVisibleDots = (Boolean) in.readValue(null);
+ mShowErrorPath = (Boolean) in.readValue(null);
}
public String getSerializedPattern() {
@@ -1060,6 +1108,14 @@ public class LockPatternView extends View {
public boolean isTactileFeedbackEnabled(){
return mTactileFeedbackEnabled;
}
+
+ public boolean isVisibleDots() {
+ return mVisibleDots;
+ }
+
+ public boolean isShowErrorPath() {
+ return mShowErrorPath;
+ }
@Override
public void writeToParcel(Parcel dest, int flags) {
@@ -1069,6 +1125,8 @@ public class LockPatternView extends View {
dest.writeValue(mInputEnabled);
dest.writeValue(mInStealthMode);
dest.writeValue(mTactileFeedbackEnabled);
+ dest.writeValue(mVisibleDots);
+ dest.writeValue(mShowErrorPath);
}
public static final Parcelable.Creator<SavedState> CREATOR =
diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java
index 131ac51..4ca92e3 100644
--- a/core/java/com/google/android/mms/pdu/PduParser.java
+++ b/core/java/com/google/android/mms/pdu/PduParser.java
@@ -163,6 +163,13 @@ public class PduParser {
// or "application/vnd.wap.multipart.related"
// or "application/vnd.wap.multipart.alternative"
return retrieveConf;
+ } else if (ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) {
+ // "application/vnd.wap.multipart.alternative"
+ // should take only the first part.
+ PduPart firstPart = mBody.getPart(0);
+ mBody.removeAll();
+ mBody.addPart(0, firstPart);
+ return retrieveConf;
}
return null;
case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
@@ -202,7 +209,18 @@ public class PduParser {
PduHeaders headers = new PduHeaders();
while (keepParsing && (pduDataStream.available() > 0)) {
+ pduDataStream.mark(1);
int headerField = extractByteValue(pduDataStream);
+ /* parse custom text header */
+ if ((headerField >= TEXT_MIN) && (headerField <= TEXT_MAX)) {
+ pduDataStream.reset();
+ byte [] bVal = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+ if (LOCAL_LOGV) {
+ Log.v(LOG_TAG, "TextHeader: " + new String(bVal));
+ }
+ /* we should ignore it at the moment */
+ continue;
+ }
switch (headerField) {
case PduHeaders.MESSAGE_TYPE:
{
@@ -780,26 +798,34 @@ public class PduParser {
/* get part's data */
if (dataLength > 0) {
byte[] partData = new byte[dataLength];
+ String partContentType = new String(part.getContentType());
pduDataStream.read(partData, 0, dataLength);
- // Check Content-Transfer-Encoding.
- byte[] partDataEncoding = part.getContentTransferEncoding();
- if (null != partDataEncoding) {
- String encoding = new String(partDataEncoding);
- if (encoding.equalsIgnoreCase(PduPart.P_BASE64)) {
- // Decode "base64" into "binary".
- partData = Base64.decodeBase64(partData);
- } else if (encoding.equalsIgnoreCase(PduPart.P_QUOTED_PRINTABLE)) {
- // Decode "quoted-printable" into "binary".
- partData = QuotedPrintable.decodeQuotedPrintable(partData);
- } else {
- // "binary" is the default encoding.
+ if (partContentType.equalsIgnoreCase(ContentType.MULTIPART_ALTERNATIVE)) {
+ // parse "multipart/vnd.wap.multipart.alternative".
+ PduBody childBody = parseParts(new ByteArrayInputStream(partData));
+ // take the first part of children.
+ part = childBody.getPart(0);
+ } else {
+ // Check Content-Transfer-Encoding.
+ byte[] partDataEncoding = part.getContentTransferEncoding();
+ if (null != partDataEncoding) {
+ String encoding = new String(partDataEncoding);
+ if (encoding.equalsIgnoreCase(PduPart.P_BASE64)) {
+ // Decode "base64" into "binary".
+ partData = Base64.decodeBase64(partData);
+ } else if (encoding.equalsIgnoreCase(PduPart.P_QUOTED_PRINTABLE)) {
+ // Decode "quoted-printable" into "binary".
+ partData = QuotedPrintable.decodeQuotedPrintable(partData);
+ } else {
+ // "binary" is the default encoding.
+ }
}
+ if (null == partData) {
+ log("Decode part data error!");
+ return null;
+ }
+ part.setData(partData);
}
- if (null == partData) {
- log("Decode part data error!");
- return null;
- }
- part.setData(partData);
}
/* add this part to body */
@@ -1531,18 +1557,36 @@ public class PduParser {
* Attachment = <Octet 129>
* Inline = <Octet 130>
*/
- int len = parseValueLength(pduDataStream);
+ int len = -1;
+ boolean validDispositionLength = true;
+ pduDataStream.mark(1);
+
+ try {
+ len = parseValueLength(pduDataStream);
+ } catch (RuntimeException e) {
+ // tolerate invalid content-disposition length
+ len = 31;
+ validDispositionLength = false;
+ pduDataStream.reset();
+ }
+
pduDataStream.mark(1);
int thisStartPos = pduDataStream.available();
int thisEndPos = 0;
int value = pduDataStream.read();
-
- if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
- part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
- } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
- part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
- } else if (value == PduPart.P_DISPOSITION_INLINE) {
- part.setContentDisposition(PduPart.DISPOSITION_INLINE);
+
+ if (validDispositionLength) {
+ if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
+ part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
+ } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
+ part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
+ } else if (value == PduPart.P_DISPOSITION_INLINE) {
+ part.setContentDisposition(PduPart.DISPOSITION_INLINE);
+ } else {
+ pduDataStream.reset();
+ /* Token-text */
+ part.setContentDisposition(parseWapString(pduDataStream, TYPE_TEXT_STRING));
+ }
} else {
pduDataStream.reset();
/* Token-text */
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index df1ab9e..bd0f307 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -120,6 +120,7 @@ LOCAL_SRC_FILES:= \
android_server_BluetoothService.cpp \
android_server_BluetoothEventLoop.cpp \
android_server_BluetoothA2dpService.cpp \
+ android_server_BluetoothHidService.cpp \
android_server_Watchdog.cpp \
android_message_digest_sha1.cpp \
android_ddm_DdmHandleNativeHeap.cpp \
@@ -162,8 +163,6 @@ LOCAL_SHARED_LIBRARIES := \
libbinder \
libnetutils \
libui \
- libsurfaceflinger_client \
- libcamera_client \
libskiagl \
libskia \
libsqlite \
@@ -184,6 +183,12 @@ LOCAL_SHARED_LIBRARIES := \
libwpa_client \
libjpeg
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client \
+ libcamera_client
+endif
+
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_C_INCLUDES += \
external/dbus \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d38d748..682f78e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -153,6 +153,7 @@ extern int register_android_bluetooth_ScoSocket(JNIEnv *env);
extern int register_android_server_BluetoothService(JNIEnv* env);
extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
+extern int register_android_server_BluetoothHidService(JNIEnv* env);
extern int register_android_server_Watchdog(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
@@ -555,7 +556,10 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
}
}
- property_get("dalvik.vm.execution-mode", propBuf, "");
+ property_get("persist.sys.jit-mode", propBuf, "");
+ if (strcmp(propBuf, "") == 0) {
+ property_get("dalvik.vm.execution-mode", propBuf, "");
+ }
if (strcmp(propBuf, "int:portable") == 0) {
executionMode = kEMIntPortable;
} else if (strcmp(propBuf, "int:fast") == 0) {
@@ -603,8 +607,12 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
//options[curOpt++].optionString = "-verbose:class";
strcpy(heapsizeOptsBuf, "-Xmx");
- property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
- //LOGI("Heap size: %s", heapsizeOptsBuf);
+ property_get("persist.sys.vm.heapsize", propBuf, "");
+ if (strcmp(propBuf, "") == 0) {
+ property_get("dalvim.vm.heapsize", propBuf, "16m");
+ }
+ strcpy(heapsizeOptsBuf+4, propBuf);
+ LOGI("Heap size: %s", heapsizeOptsBuf);
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
@@ -1277,6 +1285,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_server_BluetoothService),
REG_JNI(register_android_server_BluetoothEventLoop),
REG_JNI(register_android_server_BluetoothA2dpService),
+ REG_JNI(register_android_server_BluetoothHidService),
REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_message_digest_sha1),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
diff --git a/core/jni/CursorWindow.cpp b/core/jni/CursorWindow.cpp
index 7877921..f089583 100644
--- a/core/jni/CursorWindow.cpp
+++ b/core/jni/CursorWindow.cpp
@@ -18,9 +18,12 @@
#define LOG_TAG "CursorWindow"
#include <utils/Log.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
+#include <binder/MemoryDealer.h>
+#else
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>
-
+#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
@@ -38,7 +41,11 @@ CursorWindow::CursorWindow(size_t maxSize) :
{
}
+#ifdef USE_ECLAIR_MEMORYDEALER
+bool CursorWindow::setMemory(sp<IMemory> memory)
+#else
bool CursorWindow::setMemory(const sp<IMemory>& memory)
+#endif
{
mMemory = memory;
mData = (uint8_t *) memory->pointer();
@@ -48,6 +55,9 @@ bool CursorWindow::setMemory(const sp<IMemory>& memory)
mHeader = (window_header_t *) mData;
// Make the window read-only
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mHeap = NULL;
+#endif
ssize_t size = memory->size();
mSize = size;
mMaxSize = size;
@@ -59,11 +69,16 @@ LOG_WINDOW("Created CursorWindow from existing IMemory: mFreeOffset = %d, numRow
bool CursorWindow::initBuffer(bool localOnly)
{
//TODO Use a non-memory dealer mmap region for localOnly
-
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mHeap = new MemoryDealer(new SharedHeap(mMaxSize, 0, "CursorWindow"));
+ if (mHeap != NULL) {
+ mMemory = mHeap->allocate(mMaxSize);
+#else
sp<MemoryHeapBase> heap;
heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow");
if (heap != NULL) {
mMemory = new MemoryBase(heap, 0, mMaxSize);
+#endif
if (mMemory != NULL) {
mData = (uint8_t *) mMemory->pointer();
if (mData) {
diff --git a/core/jni/CursorWindow.h b/core/jni/CursorWindow.h
index 3fcb560..f5d791a 100644
--- a/core/jni/CursorWindow.h
+++ b/core/jni/CursorWindow.h
@@ -21,9 +21,12 @@
#include <stddef.h>
#include <stdint.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
+#include <binder/MemoryDealer.h>
+#else
#include <binder/IMemory.h>
#include <utils/RefBase.h>
-
+#endif
#include <jni.h>
#define DEFAULT_WINDOW_SIZE 4096
@@ -101,7 +104,11 @@ class CursorWindow
public:
CursorWindow(size_t maxSize);
CursorWindow(){}
+#ifdef USE_ECLAIR_MEMORYDEALER
+ bool setMemory(sp<IMemory>);
+#else
bool setMemory(const sp<IMemory>&);
+#endif
~CursorWindow();
bool initBuffer(bool localOnly);
@@ -189,6 +196,9 @@ private:
size_t mSize;
size_t mMaxSize;
window_header_t * mHeader;
+#ifdef USE_ECLAIR_MEMORYDEALER
+ sp<MemoryDealer> mHeap;
+#endif
sp<IMemory> mMemory;
/**
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index e1e9536..a528006 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -951,7 +951,7 @@ static JNINativeMethod gCanvasMethods[] = {
(void*) SkCanvasGlue::drawText___CIIFFPaint},
{"native_drawText","(ILjava/lang/String;IIFFI)V",
(void*) SkCanvasGlue::drawText__StringIIFFPaint},
- {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
+ {"native_drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
(void*) SkCanvasGlue::drawString},
{"native_drawPosText","(I[CII[FI)V",
(void*) SkCanvasGlue::drawPosText___CII_FPaint},
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index b85466b..7531dee 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -476,7 +476,8 @@ static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jst
env->ReleaseStringCritical(params, str);
}
if (camera->setParameters(params8) != NO_ERROR) {
- jniThrowException(env, "java/lang/RuntimeException", "setParameters failed");
+ LOGE("setParameters failed!");
+ //jniThrowException(env, "java/lang/RuntimeException", "setParameters failed");
return;
}
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index feb0dad..50df9d3 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -22,29 +22,8 @@
#include <utils/Log.h>
#include <arpa/inet.h>
-extern "C" {
-int ifc_enable(const char *ifname);
-int ifc_disable(const char *ifname);
-int ifc_add_host_route(const char *ifname, uint32_t addr);
-int ifc_remove_host_routes(const char *ifname);
-int ifc_set_default_route(const char *ifname, uint32_t gateway);
-int ifc_get_default_route(const char *ifname);
-int ifc_remove_default_route(const char *ifname);
-int ifc_reset_connections(const char *ifname);
-int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2);
-
-int dhcp_do_request(const char *ifname,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
- uint32_t *lease);
-int dhcp_stop(const char *ifname);
-int dhcp_release_lease(const char *ifname);
-char *dhcp_get_errmsg();
-}
+#include <netutils/ifc.h>
+#include <netutils/dhcp.h>
#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 46000c9..5903f09 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -30,23 +30,6 @@ namespace android {
static jboolean sScanModeActive = false;
-/*
- * The following remembers the jfieldID's of the fields
- * of the DhcpInfo Java object, so that we don't have
- * to look them up every time.
- */
-static struct fieldIds {
- jclass dhcpInfoClass;
- jmethodID constructorId;
- jfieldID ipaddress;
- jfieldID gateway;
- jfieldID netmask;
- jfieldID dns1;
- jfieldID dns2;
- jfieldID serverAddress;
- jfieldID leaseDuration;
-} dhcpInfoFieldIds;
-
static int doCommand(const char *cmd, char *replybuf, int replybuflen)
{
size_t reply_len = replybuflen - 1;
@@ -479,28 +462,6 @@ static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject claz
return doBooleanCommand("BLACKLIST clear", "OK");
}
-static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info)
-{
- jint ipaddr, gateway, mask, dns1, dns2, server, lease;
- jboolean succeeded = ((jboolean)::do_dhcp_request(&ipaddr, &gateway, &mask,
- &dns1, &dns2, &server, &lease) == 0);
- if (succeeded && dhcpInfoFieldIds.dhcpInfoClass != NULL) {
- env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr);
- env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway);
- env->SetIntField(info, dhcpInfoFieldIds.netmask, mask);
- env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1);
- env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2);
- env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server);
- env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease);
- }
- return succeeded;
-}
-
-static jstring android_net_wifi_getDhcpError(JNIEnv* env, jobject clazz)
-{
- return env->NewStringUTF(::get_dhcp_error_string());
-}
-
// ----------------------------------------------------------------------------
/*
@@ -556,9 +517,6 @@ static JNINativeMethod gWifiMethods[] = {
{ "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand },
{ "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand },
{ "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand },
-
- { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest },
- { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError },
};
int register_android_net_wifi_WifiManager(JNIEnv* env)
@@ -566,18 +524,6 @@ int register_android_net_wifi_WifiManager(JNIEnv* env)
jclass wifi = env->FindClass(WIFI_PKG_NAME);
LOG_FATAL_IF(wifi == NULL, "Unable to find class " WIFI_PKG_NAME);
- dhcpInfoFieldIds.dhcpInfoClass = env->FindClass("android/net/DhcpInfo");
- if (dhcpInfoFieldIds.dhcpInfoClass != NULL) {
- dhcpInfoFieldIds.constructorId = env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, "<init>", "()V");
- dhcpInfoFieldIds.ipaddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "ipAddress", "I");
- dhcpInfoFieldIds.gateway = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "gateway", "I");
- dhcpInfoFieldIds.netmask = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "netmask", "I");
- dhcpInfoFieldIds.dns1 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I");
- dhcpInfoFieldIds.dns2 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I");
- dhcpInfoFieldIds.serverAddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "serverAddress", "I");
- dhcpInfoFieldIds.leaseDuration = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "leaseDuration", "I");
- }
-
return AndroidRuntime::registerNativeMethods(env,
WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));
}
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 259cc01..7c35ff4 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -729,6 +729,7 @@ static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) {
#ifdef HAVE_BLUETOOTH
extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env);
+extern DBusHandlerResult hid_event_filter(DBusMessage *msg, JNIEnv *env);
// Called by dbus during WaitForAndDispatchEventNative()
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
@@ -853,9 +854,21 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
method_onDeviceDisconnectRequested,
env->NewStringUTF(remote_device_path));
goto success;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Input",
+ "PropertyChanged")) {
+ LOGD("Input device receive propertychnaged!!!");
}
+ if (a2dp_event_filter(msg, env) == DBUS_HANDLER_RESULT_HANDLED) {
+ ret = DBUS_HANDLER_RESULT_HANDLED;
+ } else if (hid_event_filter(msg, env) == DBUS_HANDLER_RESULT_HANDLED) {
+ ret = DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
- ret = a2dp_event_filter(msg, env);
+ //ret = a2dp_event_filter(msg, env);
env->PopLocalFrame(NULL);
return ret;
diff --git a/core/jni/android_server_BluetoothHidService.cpp b/core/jni/android_server_BluetoothHidService.cpp
new file mode 100644
index 0000000..1e54a02
--- /dev/null
+++ b/core/jni/android_server_BluetoothHidService.cpp
@@ -0,0 +1,335 @@
+/*
+** Copyright 2009 ISB Corporation
+** Copyright (C) 2010 0xlab
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 "BluetoothHidService.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jmethodID method_onPropertyChanged;
+static jmethodID method_onHidDeviceConnected;
+static jmethodID method_onHidDeviceDisconnected;
+
+typedef struct {
+ JavaVM *vm;
+ int envVer;
+ DBusConnection *conn;
+ jobject me; // for callbacks to java
+} native_data_t;
+
+static native_data_t *nat = NULL; // global native data
+static Properties hid_properties[] = {
+ {"Connected", DBUS_TYPE_BOOLEAN},
+ };
+static void onConnectHidDeviceResult(DBusMessage *msg, void *user, void *nat);
+static void onDisconnectHidDeviceResult(DBusMessage *msg, void *user, void *nat);
+#endif
+
+
+/* Returns true on success (even if adapter is present but disabled).
+ * Return false if dbus is down, or another serious error (out of memory)
+*/
+static bool initNative(JNIEnv* env, jobject object) {
+ LOGD(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return false;
+ }
+ env->GetJavaVM( &(nat->vm) );
+ nat->envVer = env->GetVersion();
+ nat->me = env->NewGlobalRef(object);
+
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_threads_init_default();
+ nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ LOGE("Could not get onto the system bus: %s", err.message);
+ dbus_error_free(&err);
+ return false;
+ }
+#endif /*HAVE_BLUETOOTH*/
+ return true;
+}
+
+static void cleanupNative(JNIEnv* env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGD(__FUNCTION__);
+ if (nat) {
+ dbus_connection_close(nat->conn);
+ env->DeleteGlobalRef(nat->me);
+ free(nat);
+ nat = NULL;
+ }
+#endif
+}
+
+static jobjectArray getHidPropertiesNative(JNIEnv *env, jobject object,
+ jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGD(__FUNCTION__);
+ if (nat) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
+
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ reply = dbus_func_args_timeout(env,
+ nat->conn, -1, c_path,
+ "org.bluez.Input", "GetProperties",
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+ if (!reply && dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ return NULL;
+ } else if (!reply) {
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return NULL;
+ }
+ DBusMessageIter iter;
+ if (dbus_message_iter_init(reply, &iter))
+ return parse_properties(env, &iter, (Properties *)&hid_properties,
+ sizeof(hid_properties) / sizeof(Properties));
+ }
+#endif
+ return NULL;
+}
+
+static jboolean connectHidDeviceNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGD(__FUNCTION__);
+ if (nat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ size_t path_sz = env->GetStringUTFLength(path) + 1;
+ char *c_path_copy = (char *)malloc(path_sz); // callback data
+ strncpy(c_path_copy, c_path, path_sz);
+
+ bool ret =
+ dbus_func_args_async(env, nat->conn, -1, onConnectHidDeviceResult,
+ (void *)c_path_copy, nat,
+ c_path, "org.bluez.Input",
+ "Connect", DBUS_TYPE_INVALID);
+
+ env->ReleaseStringUTFChars(path, c_path);
+ if (!ret) {
+ free(c_path_copy);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean disconnectHidDeviceNative(JNIEnv *env, jobject object,
+ jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGD(__FUNCTION__);
+ if (nat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+
+ bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+ c_path, "org.bluez.Input", "Disconnect",
+ DBUS_TYPE_INVALID);
+ LOGD("... path = %s", c_path);
+ env->ReleaseStringUTFChars(path, c_path);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+
+#ifdef HAVE_BLUETOOTH
+
+static void onConnectHidDeviceResult(DBusMessage *msg, void *user, void *natData) {
+ LOGD(__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);
+
+ LOGD("... path = %s", c_path);
+ if (dbus_set_error_from_message(&err, msg)) {
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ dbus_error_free(&err);
+ env->CallVoidMethod(nat->me,
+ method_onHidDeviceDisconnected,
+ env->NewStringUTF(c_path));
+ if (env->ExceptionCheck()) {
+ LOGE("VM Exception occurred in native function %s (%s:%d)",
+ __FUNCTION__, __FILE__, __LINE__);
+ }
+ } else { // else Java callback is triggered by signal in hid_event_filter?
+ env->CallVoidMethod(nat->me,
+ method_onHidDeviceConnected,
+ env->NewStringUTF(c_path));
+ }
+
+ free(c_path);
+}
+
+static void onDisconnectHidDeviceResult(DBusMessage *msg, void *user, void *natData) {
+ LOGD(__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);
+
+ LOGD("... path = %s", c_path);
+ if (dbus_set_error_from_message(&err, msg)) {
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ if (strcmp(err.name, "org.bluez.Error.NotConnected") == 0) {
+ // we were already disconnected, so report disconnect
+ env->CallVoidMethod(nat->me,
+ method_onHidDeviceDisconnected,
+ env->NewStringUTF(c_path));
+ } else {
+ // Assume it is still connected
+ env->CallVoidMethod(nat->me,
+ method_onHidDeviceConnected,
+ env->NewStringUTF(c_path));
+ }
+ dbus_error_free(&err);
+ if (env->ExceptionCheck()) {
+ LOGE("VM Exception occurred in native function %s (%s:%d)",
+ __FUNCTION__, __FILE__, __LINE__);
+ }
+ } else { // else Java callback is triggered by signal in hid_event_filter?
+ env->CallVoidMethod(nat->me,
+ method_onHidDeviceDisconnected,
+ env->NewStringUTF(c_path));
+ }
+ free(c_path);
+}
+
+DBusHandlerResult hid_event_filter(DBusMessage *msg, JNIEnv *env) {
+ DBusError err;
+ LOGD("hid_event_filter...");
+ if (!nat) {
+ LOGE("... skipping %s\n", __FUNCTION__);
+ LOGE("... ignored\n");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ dbus_error_init(&err);
+
+ if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_is_signal(msg, "org.bluez.Input",
+ "PropertyChanged")) {
+ jobjectArray str_array =
+ parse_property_change(env, msg, (Properties *)&hid_properties,
+ sizeof(hid_properties) / sizeof(Properties));
+ const char *c_path = dbus_message_get_path(msg);
+ LOGD("received org.bluez.Input PropertyChanged...");
+ jstring path = env->NewStringUTF(c_path);
+
+ env->CallVoidMethod(nat->me,
+ method_onPropertyChanged,
+ path,
+ str_array);
+
+ env->DeleteLocalRef(path);
+
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ return result;
+ } else {
+ LOGV("... ignored");
+ }
+ if (env->ExceptionCheck()) {
+ LOGE("VM Exception occurred while handling %s.%s (%s) in %s,"
+ " leaving for VM",
+ dbus_message_get_interface(msg), dbus_message_get_member(msg),
+ dbus_message_get_path(msg), __FUNCTION__);
+ }
+
+ return result;
+}
+#endif
+
+
+static JNINativeMethod sMethods[] = {
+ {"initNative", "()Z", (void *)initNative},
+ {"cleanupNative", "()V", (void *)cleanupNative},
+
+
+ {"connectHidDeviceNative", "(Ljava/lang/String;)Z", (void*)connectHidDeviceNative},
+ {"disconnectHidDeviceNative", "(Ljava/lang/String;)Z", (void*)disconnectHidDeviceNative},
+ {"getHidPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
+ (void *)getHidPropertiesNative},
+};
+
+
+int register_android_server_BluetoothHidService(JNIEnv *env) {
+ jclass clazz = env->FindClass("android/server/BluetoothHidService");
+ if (clazz == NULL) {
+ LOGE("Can't find android/server/BluetoothHidService");
+ return -1;
+ }
+
+#ifdef HAVE_BLUETOOTH
+ method_onHidDeviceConnected = env->GetMethodID(clazz, "onHidDeviceConnected", "(Ljava/lang/String;)V");
+ method_onHidDeviceDisconnected = env->GetMethodID(clazz, "onHidDeviceDisconnected", "(Ljava/lang/String;)V");
+ method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
+ "(Ljava/lang/String;[Ljava/lang/String;)V");
+#endif
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothHidService", sMethods, NELEM(sMethods));
+}
+
+
+} /* namespace android */
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 200a1b2..70375f9 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -131,12 +131,23 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:drawablePadding="4dip"
/>
+
+ <TextView
+ android:id="@+id/customMsg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4.0dip"
+ android:layout_marginLeft="24dip"
+ android:layout_marginRight="24dip"
+ android:layout_below="@id/status2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
<TextView
android:id="@+id/screenLocked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@id/status2"
+ android:layout_below="@id/customMsg"
android:layout_marginLeft="24dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_marginTop="12dip"
@@ -167,5 +178,56 @@
android:visibility="gone"
/>
+ <!-- music control buttons -->
+ <ImageButton
+ android:id="@+id/musicControlPlay"
+ android:src="@drawable/ic_media_play"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/musicControlPause"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_media_pause"
+ android:layout_centerInParent="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/musicControlPrevious"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_media_previous"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:layout_toLeftOf="@+id/musicControlPause"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/musicControlNext"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_media_next"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:layout_toRightOf="@+id/musicControlPause"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
+
+
</RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 23505c2..1e5884d 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -130,17 +130,75 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:drawablePadding="4dip"
/>
+
+ <TextView
+ android:id="@+id/customMsg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4.0dip"
+ android:layout_below="@id/status2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
<TextView
android:id="@+id/screenLocked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@id/status2"
+ android:layout_below="@id/customMsg"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"
android:layout_marginTop="12dip"
android:drawablePadding="4dip"
/>
+ <!-- music control buttons -->
+ <ImageButton
+ android:id="@+id/musicControlPlay"
+ android:src="@drawable/ic_media_play"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/musicControlPause"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_media_pause"
+ android:layout_centerInParent="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/musicControlPrevious"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_media_previous"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:layout_toLeftOf="@+id/musicControlPause"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
+ <ImageButton
+ android:id="@+id/musicControlNext"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_media_next"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="20dip"
+ android:padding="10px"
+ android:layout_toRightOf="@+id/musicControlPause"
+ android:background="@color/transparent"
+ android:visibility="gone"
+ />
</RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index b5cd442..f512378 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -137,6 +137,13 @@
android:drawablePadding="4dip"
/>
</LinearLayout>
+
+ <TextView
+ android:id="@+id/customMsg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
<!-- fill space between header and button below -->
<View
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 9ac0a47..9f99fec 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -100,6 +100,17 @@
/>
</RelativeLayout>
+
+ <TextView
+ android:id="@+id/customMsg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dip"
+ android:layout_marginLeft="24dip"
+ android:layout_marginRight="24dip"
+ android:layout_below="@id/status2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
<View
android:id="@+id/divider"
diff --git a/core/res/res/layout/recent_apps_dialog.xml b/core/res/res/layout/recent_apps_dialog.xml
index e3492f6..dece5ec 100644
--- a/core/res/res/layout/recent_apps_dialog.xml
+++ b/core/res/res/layout/recent_apps_dialog.xml
@@ -28,6 +28,7 @@
<!-- Title -->
<TextView
+ android:id="@+id/recent_title"
android:layout_width="wrap_content"
android:layout_height="40dip"
android:gravity="center"
diff --git a/core/res/res/layout/recent_apps_dialog_12.xml b/core/res/res/layout/recent_apps_dialog_12.xml
new file mode 100644
index 0000000..66db0b8
--- /dev/null
+++ b/core/res/res/layout/recent_apps_dialog_12.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<com.android.internal.policy.impl.RecentApplicationsBackground
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@drawable/recent_dialog_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:padding="4dip"
+ android:orientation="vertical">
+
+ <!-- Title -->
+ <TextView
+ android:id="@+id/recent_title"
+ android:layout_width="wrap_content"
+ android:layout_height="20dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="#80FFFFFF"
+ android:textStyle="bold"
+ android:singleLine="true"
+ android:text="@android:string/recent_tasks_title" />
+
+ <!-- This is only intended to be visible when all buttons (below) are invisible -->
+ <TextView
+ android:id="@+id/no_applications_message"
+ android:layout_width="320dip"
+ android:layout_height="80dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@android:string/no_recent_tasks" />
+
+ <!-- The first row has a fixed-width because the UI spec requires the box
+ to display with full-width no matter how many icons are visible, but to
+ adjust height based on number of rows. -->
+ <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
+ <LinearLayout
+ android:layout_width="320dip"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button0" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button1" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button2" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button3" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="320dp"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button4" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button5" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button6" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button7" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="320dp"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button8" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button9" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button10" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_12"
+ android:id="@+id/button11" />
+
+ </LinearLayout>
+
+ <!-- spacer to balance out the title above -->
+ <FrameLayout
+ android:layout_height="20dip"
+ android:layout_width="match_parent"
+ />
+</com.android.internal.policy.impl.RecentApplicationsBackground>
diff --git a/core/res/res/layout/recent_apps_dialog_15.xml b/core/res/res/layout/recent_apps_dialog_15.xml
new file mode 100644
index 0000000..ee0f33e
--- /dev/null
+++ b/core/res/res/layout/recent_apps_dialog_15.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<com.android.internal.policy.impl.RecentApplicationsBackground
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@drawable/recent_dialog_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:padding="4dip"
+ android:orientation="vertical">
+
+ <!-- Title -->
+ <TextView
+ android:id="@+id/recent_title"
+ android:layout_width="wrap_content"
+ android:layout_height="20dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="#80FFFFFF"
+ android:textStyle="bold"
+ android:singleLine="true"
+ android:text="@android:string/recent_tasks_title" />
+
+ <!-- This is only intended to be visible when all buttons (below) are invisible -->
+ <TextView
+ android:id="@+id/no_applications_message"
+ android:layout_width="320dip"
+ android:layout_height="80dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@android:string/no_recent_tasks" />
+
+ <!-- The first row has a fixed-width because the UI spec requires the box
+ to display with full-width no matter how many icons are visible, but to
+ adjust height based on number of rows. -->
+ <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
+ <LinearLayout
+ android:layout_width="320dip"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button0" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button1" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button2" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button3" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button4" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="320dp"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button5" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button6" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button7" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button8" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button9" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="320dp"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button10" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button11" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button12" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button13" />
+
+ <include
+ layout="@android:layout/recent_apps_icon_15"
+ android:id="@+id/button14" />
+
+ </LinearLayout>
+
+ <!-- spacer to balance out the title above -->
+ <FrameLayout
+ android:layout_height="20dip"
+ android:layout_width="match_parent"
+ />
+</com.android.internal.policy.impl.RecentApplicationsBackground>
diff --git a/core/res/res/layout/recent_apps_icon_12.xml b/core/res/res/layout/recent_apps_icon_12.xml
new file mode 100644
index 0000000..c9501e1
--- /dev/null
+++ b/core/res/res/layout/recent_apps_icon_12.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<!-- This is not a standalone element - it is imported into recent_apps_dialog.xml -->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/label"
+ style="?android:attr/buttonStyle"
+ android:background="#00000000"
+ android:layout_width="80dip"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dip"
+ android:layout_marginBottom="3dip"
+ android:textColor="@color/bright_foreground_dark"
+
+ android:paddingTop="0dip"
+ android:paddingBottom="0dip"
+ android:drawablePadding="4dip"
+
+ android:textSize="11dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:gravity="top|center_horizontal" />
diff --git a/core/res/res/layout/recent_apps_icon_15.xml b/core/res/res/layout/recent_apps_icon_15.xml
new file mode 100644
index 0000000..8ec38f5
--- /dev/null
+++ b/core/res/res/layout/recent_apps_icon_15.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<!-- This is not a standalone element - it is imported into recent_apps_dialog.xml -->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/label"
+ style="?android:attr/buttonStyle"
+ android:background="#00000000"
+ android:layout_width="64dip"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dip"
+ android:layout_marginBottom="3dip"
+ android:textColor="@color/bright_foreground_dark"
+
+ android:paddingTop="0dip"
+ android:paddingBottom="0dip"
+ android:drawablePadding="4dip"
+
+ android:textSize="11dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:gravity="top|center_horizontal" />
diff --git a/core/res/res/layout/status_bar_expanded.xml b/core/res/res/layout/status_bar_expanded.xml
index 30138a7..b20492a 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/core/res/res/layout/status_bar_expanded.xml
@@ -24,7 +24,7 @@
android:descendantFocusability="afterDescendants"
>
- <LinearLayout
+ <LinearLayout android:id="@+id/exp_view_lin_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
diff --git a/core/res/res/layout/status_bar_tracking.xml b/core/res/res/layout/status_bar_tracking.xml
index c0a7a97..b15ee39 100644
--- a/core/res/res/layout/status_bar_tracking.xml
+++ b/core/res/res/layout/status_bar_tracking.xml
@@ -36,7 +36,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
>
- <ImageView
+ <ImageView android:id="@+id/close_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 11095c0..da06ba5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -134,11 +134,23 @@
<string name="power_off" msgid="4266614107412865048">"Ausschalten"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Wird heruntergefahren..."</string>
<string name="shutdown_confirm" msgid="649792175242821353">"Ihr Telefon wird heruntergefahren."</string>
+
+ <!-- Button to reboot the phone, within the Phone Options dialog -->
+ <string name="reboot_system">Neu starten</string>
+ <!-- Reboot Progress Dialog. This is shown if the user chooses to reboot the phone. -->
+ <string name="reboot_progress">Neu starten...</string>
+ <!-- Reboot Confirmation Dialog. When the user chooses to reboot the phone, there will be a confirmation dialog. This is the message. -->
+ <string name="reboot_confirm">Ihr Telefon wird neu gestartet.</string>
+
<string name="recent_tasks_title" msgid="3691764623638127888">"Zuletzt verwendet"</string>
<string name="no_recent_tasks" msgid="279702952298056674">"Keine zuletzt verwendeten Anwendungen"</string>
<string name="global_actions" msgid="2406416831541615258">"Telefonoptionen"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Display-Sperre"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
+
+ <!-- label for item that reboots the phone in phone options dialog -->
+ <string name="global_action_reboot">Neu starten</string>
+
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lautlos"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ton ist AUS"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ton ist AN"</string>
@@ -861,4 +873,7 @@
<string name="throttle_warning_notification_message" msgid="2609734763845705708">"Weitere Informationen über die Mobildatennutzung durch Berühren aufrufen"</string>
<string name="throttled_notification_title" msgid="6269541897729781332">"Mobildatenlimit überschritten"</string>
<string name="throttled_notification_message" msgid="4712369856601275146">"Weitere Informationen über die Mobildatennutzung durch Berühren aufrufen"</string>
+
+ <!-- Reboot recommended after applying color changes (CM) -->
+ <string name="toast_reboot_recommend">Achtung: Neustart wird empfohlen nach Beendigung der Anpassungen!</string>
</resources>
diff --git a/core/res/res/values-he-rIL/donottranslate-cldr.xml b/core/res/res/values-he-rIL/donottranslate-cldr.xml
new file mode 100644
index 0000000..89cbf42
--- /dev/null
+++ b/core/res/res/values-he-rIL/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">ינואר</string>
+ <string name="month_long_standalone_february">פברואר</string>
+ <string name="month_long_standalone_march">מרץ</string>
+ <string name="month_long_standalone_april">אפריל</string>
+ <string name="month_long_standalone_may">מאי</string>
+ <string name="month_long_standalone_june">יוני</string>
+ <string name="month_long_standalone_july">יולי</string>
+ <string name="month_long_standalone_august">אוגוסט</string>
+ <string name="month_long_standalone_september">ספטמבר</string>
+ <string name="month_long_standalone_october">אוקטובר</string>
+ <string name="month_long_standalone_november">נובמבר</string>
+ <string name="month_long_standalone_december">דצמבר</string>
+
+ <string name="month_long_january">ינואר</string>
+ <string name="month_long_february">פברואר</string>
+ <string name="month_long_march">מרץ</string>
+ <string name="month_long_april">אפריל</string>
+ <string name="month_long_may">מאי</string>
+ <string name="month_long_june">יוני</string>
+ <string name="month_long_july">יולי</string>
+ <string name="month_long_august">אוגוסט</string>
+ <string name="month_long_september">ספטמבר</string>
+ <string name="month_long_october">אוקטובר</string>
+ <string name="month_long_november">נובמבר</string>
+ <string name="month_long_december">דצמבר</string>
+
+ <string name="month_medium_january">ינו</string>
+ <string name="month_medium_february">פבר</string>
+ <string name="month_medium_march">מרץ</string>
+ <string name="month_medium_april">אפר</string>
+ <string name="month_medium_may">מאי</string>
+ <string name="month_medium_june">יונ</string>
+ <string name="month_medium_july">יול</string>
+ <string name="month_medium_august">אוג</string>
+ <string name="month_medium_september">ספט</string>
+ <string name="month_medium_october">אוק</string>
+ <string name="month_medium_november">נוב</string>
+ <string name="month_medium_december">דצמ</string>
+
+ <string name="month_shortest_january">י</string>
+ <string name="month_shortest_february">פ</string>
+ <string name="month_shortest_march">מ</string>
+ <string name="month_shortest_april">א</string>
+ <string name="month_shortest_may">מ</string>
+ <string name="month_shortest_june">י</string>
+ <string name="month_shortest_july">י</string>
+ <string name="month_shortest_august">א</string>
+ <string name="month_shortest_september">ס</string>
+ <string name="month_shortest_october">א</string>
+ <string name="month_shortest_november">נ</string>
+ <string name="month_shortest_december">ד</string>
+
+ <string name="day_of_week_long_sunday">יום ראשון</string>
+ <string name="day_of_week_long_monday">יום שני</string>
+ <string name="day_of_week_long_tuesday">יום שלישי</string>
+ <string name="day_of_week_long_wednesday">יום רביעי</string>
+ <string name="day_of_week_long_thursday">יום חמישי</string>
+ <string name="day_of_week_long_friday">יום שישי</string>
+ <string name="day_of_week_long_saturday">יום שבת</string>
+
+ <string name="day_of_week_medium_sunday">ראשון</string>
+ <string name="day_of_week_medium_monday">שני</string>
+ <string name="day_of_week_medium_tuesday">שלי</string>
+ <string name="day_of_week_medium_wednesday">רבי</string>
+ <string name="day_of_week_medium_thursday">חמי</string>
+ <string name="day_of_week_medium_friday">שיש</string>
+ <string name="day_of_week_medium_saturday">שבת</string>
+
+ <string name="day_of_week_short_sunday">Su</string>
+ <string name="day_of_week_short_monday">Mo</string>
+ <string name="day_of_week_short_tuesday">Tu</string>
+ <string name="day_of_week_short_wednesday">We</string>
+ <string name="day_of_week_short_thursday">Th</string>
+ <string name="day_of_week_short_friday">Fr</string>
+ <string name="day_of_week_short_saturday">Sa</string>
+
+ <string name="day_of_week_shortest_sunday">S</string>
+ <string name="day_of_week_shortest_monday">M</string>
+ <string name="day_of_week_shortest_tuesday">T</string>
+ <string name="day_of_week_shortest_wednesday">W</string>
+ <string name="day_of_week_shortest_thursday">T</string>
+ <string name="day_of_week_shortest_friday">F</string>
+ <string name="day_of_week_shortest_saturday">S</string>
+
+ <string name="am">am</string>
+ <string name="pm">pm</string>
+ <string name="yesterday">אתמול</string>
+ <string name="today">היום</string>
+ <string name="tomorrow">מחר</string>
+
+ <string name="hour_minute_24">%H:%M</string>
+ <string name="hour_minute_ampm">%-l:%M%p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M%^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">HH:mm</string>
+ <string name="numeric_date">%-e/%-m/%Y</string>
+ <string name="numeric_date_format">d/M/yyyy</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="month_day_year">%B %-e, %Y</string>
+ <string name="time_of_day">%-l:%M:%S %p</string>
+ <string name="date_and_time">%b %-e, %Y, %-l:%M:%S %p</string>
+ <string name="date_time">%1$s, %2$s</string>
+ <string name="time_date">%1$s, %3$s</string>
+ <string name="abbrev_month_day_year">%b %-e, %Y</string>
+ <string name="month_day">%B %-e</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%b %-e</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%2$s/%3$s – %7$s/%8$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s/%3$s – %6$s, %7$s/%8$s</string>
+ <string name="numeric_mdy1_mdy2">%2$s/%3$s/%4$s – %7$s/%8$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %2$s/%3$s/%4$s – %6$s, %7$s/%8$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s/%3$s/%4$s, %5$s – %6$s, %7$s/%8$s/%9$s, %10$s</string>
+ <string name="numeric_md1_time1_md2_time2">%2$s/%3$s, %5$s – %7$s/%8$s, %10$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s/%3$s, %5$s – %6$s, %7$s/%8$s, %10$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%2$s/%3$s/%4$s, %5$s – %7$s/%8$s/%9$s, %10$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s – %4$s, %5$s, %6$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s – %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%2$s, %3$s – %5$s, %6$s</string>
+ <string name="time_wday_date">%1$s, %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s, %2$s</string>
+ <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %2$s %3$s – %6$s, %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%2$s %3$s, %5$s – %7$s %8$s, %10$s</string>
+ <string name="same_month_md1_time1_md2_time2">%2$s %3$s, %5$s – %7$s %8$s, %10$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s – %6$s, %7$s %8$s, %10$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s – %6$s, %7$s %8$s, %10$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%2$s %3$s, %4$s, %5$s – %7$s %8$s, %9$s, %10$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%2$s %3$s, %4$s, %5$s – %7$s %8$s, %9$s, %10$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s – %6$s, %7$s %8$s, %9$s, %10$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s – %6$s, %7$s %8$s, %9$s, %10$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s, %4$s – %6$s, %7$s %8$s, %9$s</string>
+ <string name="same_month_md1_md2">%2$s %3$s – %8$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %2$s %3$s – %6$s, %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%2$s %3$s – %7$s %8$s, %9$s</string>
+ <string name="same_month_mdy1_mdy2">%2$s %3$s – %8$s, %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">d, MMMM, EEEE</string>
+ <string name="abbrev_wday_month_day_year">d, MMM, EEE, yyyy</string>
+</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d0b3b8a..2dd5a37 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -134,11 +134,15 @@
<string name="power_off" msgid="4266614107412865048">"Spegni"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Spegnimento..."</string>
<string name="shutdown_confirm" msgid="649792175242821353">"Il telefono verrà spento."</string>
+ <string name="reboot_system">Riavvia</string>
+ <string name="reboot_progress">Riavvio in corso\u2026</string>
+ <string name="reboot_confirm">Il telefono verrà riavviato.</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Recenti"</string>
<string name="no_recent_tasks" msgid="279702952298056674">"Nessuna applicazione recente."</string>
<string name="global_actions" msgid="2406416831541615258">"Opzioni telefono"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Blocco schermo"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
+ <string name="global_action_reboot">Riavvia</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modalità silenziosa"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Audio non attivo"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Audio attivo"</string>
@@ -861,4 +865,7 @@
<string name="throttle_warning_notification_message" msgid="2609734763845705708">"Tocca per informazioni sull\'utilizzo dati cell."</string>
<string name="throttled_notification_title" msgid="6269541897729781332">"Limite dati cell. superato"</string>
<string name="throttled_notification_message" msgid="4712369856601275146">"Tocca per informazioni sull\'utilizzo dati cell."</string>
+
+ <!-- Reboot recommended after applying color changes (CM) -->
+ <string name="toast_reboot_recommend">Attenzione: Riavvio richiesto dopo aver finito la personalizzazione!</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 5816ef7..62cefcc 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -132,13 +132,17 @@
<string name="turn_off_radio" msgid="8198784949987062346">"ワイヤレス接続をOFFにする"</string>
<string name="screen_lock" msgid="799094655496098153">"画面をロック"</string>
<string name="power_off" msgid="4266614107412865048">"電源を切る"</string>
+ <string name="reboot_system">"再起動する"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"シャットダウン中..."</string>
<string name="shutdown_confirm" msgid="649792175242821353">"携帯電話の電源を切ります。"</string>
+ <string name="reboot_progress">"再起動中..."</string>
+ <string name="reboot_confirm">"携帯電話を再起動します。"</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"新着"</string>
<string name="no_recent_tasks" msgid="279702952298056674">"最近使ったアプリケーションはありません。"</string>
<string name="global_actions" msgid="2406416831541615258">"携帯電話オプション"</string>
<string name="global_action_lock" msgid="2844945191792119712">"画面ロック"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"電源を切る"</string>
+ <string name="global_action_reboot">"再起動する"</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"マナーモード"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"サウンドOFF"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"サウンドON"</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 4672c0e..4ec1f40 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -126,13 +126,14 @@
<item><xliff:g id="id">battery</xliff:g></item>
<item><xliff:g id="id">phone_signal</xliff:g></item>
<item><xliff:g id="id">phone_evdo_signal</xliff:g></item>
+ <item><xliff:g id="id">phone_dbm_signal</xliff:g></item>
<item><xliff:g id="id">data_connection</xliff:g></item>
<item><xliff:g id="id">cdma_eri</xliff:g></item>
+ <item><xliff:g id="id">wifi</xliff:g></item>
<item><xliff:g id="id">tty</xliff:g></item>
<item><xliff:g id="id">volume</xliff:g></item>
<item><xliff:g id="id">mute</xliff:g></item>
<item><xliff:g id="id">speakerphone</xliff:g></item>
- <item><xliff:g id="id">wifi</xliff:g></item>
<item><xliff:g id="id">tty</xliff:g></item>
<item><xliff:g id="id">bluetooth</xliff:g></item>
<item><xliff:g id="id">gps</xliff:g></item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6d6c47f..f69e0e7 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -916,6 +916,15 @@
<enum name="KEYCODE_MEDIA_REWIND" value="89" />
<enum name="KEYCODE_MEDIA_FAST_FORWARD" value="90" />
<enum name="KEYCODE_MUTE" value="91" />
+ <enum name="KEYCODE_FUNC_1" value="92" />
+ <enum name="KEYCODE_FUNC_2" value="93" />
+ <enum name="KEYCODE_FUNC_3" value="94" />
+ <enum name="KEYCODE_FUNC_4" value="95" />
+ <enum name="KEYCODE_FUNC_5" value="96" />
+ <enum name="KEYCODE_FUNC_6" value="97" />
+ <enum name="KEYCODE_FUNC_7" value="98" />
+ <enum name="KEYCODE_FUNC_8" value="99" />
+ <enum name="KEYCODE_QUECHAR" value="100" />
</attr>
<!-- ***************************************************************** -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 088ab44..922defd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -210,6 +210,12 @@
<item>10</item>
</integer-array>
+ <!-- Vibrator pattern for feedback about on a key release -->
+ <integer-array name="config_virtualKeyUpPattern">
+ <item>5</item>
+ <item>18</item>
+ </integer-array>
+
<bool name="config_use_strict_phone_number_comparation">false</bool>
<!-- Display low battery warning when battery level dips to this value -->
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
index a94fb58..6131fbe 100644
--- a/core/res/res/values/donottranslate-cldr.xml
+++ b/core/res/res/values/donottranslate-cldr.xml
@@ -95,6 +95,7 @@
<string name="hour_minute_ampm">%-l:%M%p</string>
<string name="hour_minute_cap_ampm">%-l:%M%^p</string>
<string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twelve_hour_time_format_no_period">h:mm</string>
<string name="twenty_four_hour_time_format">HH:mm</string>
<string name="numeric_date">%-m/%-e/%Y</string>
<string name="numeric_date_format">M/d/yyyy</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 86bfe94..776255c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -272,13 +272,21 @@
<string name="screen_lock">Screen lock</string>
<!-- Button to turn off the phone, within the Phone Options dialog -->
<string name="power_off">Power off</string>
+ <!-- Button to reboot the phone, within the Phone Options dialog -->
+ <string name="reboot_system">Reboot phone</string>
<!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
<string name="shutdown_progress">Shutting down\u2026</string>
+ <!-- Reboot Progress Dialog. This is shown if the user chooses to reboot the phone. -->
+ <string name="reboot_progress">Rebooting\u2026</string>
+
<!-- Shutdown Confirmation Dialog. When the user chooses to power off the phone, there will be a confirmation dialog. This is the message. -->
<string name="shutdown_confirm">Your phone will shut down.</string>
+ <!-- Reboot Confirmation Dialog. When the user chooses to reboot the phone, there will be a confirmation dialog. This is the message. -->
+ <string name="reboot_confirm">Your phone will reboot.</string>
+
<!-- Recent Tasks dialog: title -->
<string name="recent_tasks_title">Recent</string>
<!-- Recent Tasks dialog: message when there are no recent applications -->
@@ -293,6 +301,9 @@
<!-- label for item that turns off power in phone options dialog -->
<string name="global_action_power_off">Power off</string>
+ <!-- label for item that reboots the phone in phone options dialog -->
+ <string name="global_action_reboot">Reboot</string>
+
<!-- label for item that enables silent mode in phone options dialog -->
<string name="global_action_toggle_silent_mode">Silent mode</string>
@@ -2235,6 +2246,7 @@
<string name="l2tp_vpn_description">Layer 2 Tunneling Protocol</string>
<string name="l2tp_ipsec_psk_vpn_description">Pre-shared key based L2TP/IPSec VPN</string>
<string name="l2tp_ipsec_crt_vpn_description">Certificate based L2TP/IPSec VPN</string>
+ <string name="openvpn_vpn_description">OpenVPN SSL VPN</string>
<!-- Localized strings for WebView -->
<!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
@@ -2269,4 +2281,7 @@
<!-- Shown when the users bandwidth is reduced because of excessive data use -->
<string name="throttled_notification_title">Mobile data limit exceeded</string>
<string name="throttled_notification_message">Touch to learn more about mobile data use</string>
+
+ <!-- Reboot recommended after applying color changes (CM) -->
+ <string name="toast_reboot_recommend">Caution: Reboot recommended after finishing customization!</string>
</resources>
diff --git a/core/tests/coretests/src/android/preference/ListPreferenceTest.java b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
new file mode 100644
index 0000000..41f8e03
--- /dev/null
+++ b/core/tests/coretests/src/android/preference/ListPreferenceTest.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.preference;
+
+import android.preference.ListPreference;
+import android.test.AndroidTestCase;
+
+public class ListPreferenceTest extends AndroidTestCase {
+ public void testListPreferenceSummaryFromEntries() {
+ String[] entries = { "one", "two", "three" };
+ String[] entryValues = { "1" , "2", "3" };
+ ListPreference lp = new ListPreference(getContext());
+ lp.setEntries(entries);
+ lp.setEntryValues(entryValues);
+
+ lp.setValue(entryValues[1]);
+ assertTrue(lp.getSummary() == null);
+
+ lp.setSummary("%1$s");
+ assertEquals(entries[1], lp.getSummary());
+
+ lp.setValue(entryValues[2]);
+ assertEquals(entries[2], lp.getSummary());
+
+ lp.setSummary(null);
+ assertTrue(lp.getSummary() == null);
+
+ lp.setSummary("The color is %1$s");
+ assertEquals("The color is " + entries[2], lp.getSummary());
+ }
+}
diff --git a/docs/html/resources/articles/painless-threading.jd b/docs/html/resources/articles/painless-threading.jd
index 921f4df..17cec35 100644
--- a/docs/html/resources/articles/painless-threading.jd
+++ b/docs/html/resources/articles/painless-threading.jd
@@ -108,7 +108,7 @@ you. Our previous example can easily be rewritten with
new DownloadImageTask().execute("http://example.com/image.png");
}
-private class DownloadImageTask extends AsyncTask&lt;string, void,="" bitmap=""&gt; {
+private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
diff --git a/graphics/java/android/graphics/ArabicReshape.java b/graphics/java/android/graphics/ArabicReshape.java
new file mode 100644
index 0000000..d89985c
--- /dev/null
+++ b/graphics/java/android/graphics/ArabicReshape.java
@@ -0,0 +1,448 @@
+/* @hide */
+package android.graphics;
+
+/*
+This code is for Arabic Reshaping.
+Writtien by Abdulaziz Alhussien.
+azizanroid@gmail.com
+
+This code is used in Mirsal, Ibrahim Keyboard, Arabic Contact, Arabic notepad applications
+
+
+@hide
+*/
+class ArabicReshape {
+
+
+ static final char RIGHT_LEFT_CHAR= 0x0001;
+ static final char RIGHT_NOLEFT_CHAR_ALEF=0x0006;
+ static final char RIGHT_NOLEFT_CHAR=0x0004;
+ static final char RIGHT_LEFT_CHAR_LAM=0x0003;
+ static final char TANWEEN=0x000C;
+ static final char TASHKEEL=0x000A;
+ static final char TATWEEL_CHAR= 0x0008;
+ static final char NORIGHT_NOLEFT_CHAR= 0x0007;
+ static final char NOTUSED_CHAR= 0x000F;
+ static final char NOTARABIC_CHAR= 0x0000;
+
+ static final char RIGHT_LEFT_CHAR_MASK= 0x0880;
+ static final char RIGHT_NOLEFT_CHAR_MASK= 0x0800;
+ static final char LEFT_CHAR_MASK= 0x0080;
+
+
+
+
+
+ private static final char allchar[][] = {
+ {0x0621, 0x0007, 0xFE80, 0xFE80, 0xFE80, 0xFE80},
+ {0x0622, 0x0806, 0xFE81, 0xFE82, 0xFEF5, 0xFEF6},
+ {0x0623, 0x0806, 0xFE83, 0xFE84, 0xFEF7, 0xFEF8},
+ {0x0624, 0x0804, 0xFE85, 0xFE86, 0xFE86, 0xFE86},
+ {0x0625, 0x0806, 0xFE87, 0xFE88, 0xFEF9, 0xFEFA},
+ {0x0626, 0x0881, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C},
+ {0x0627, 0x0806, 0xFE8D, 0xFE8E, 0xFEFB, 0xFEFC},
+ {0x0628, 0x0881, 0xFE8F, 0xFE90, 0xFE91, 0xFE92},
+ {0x0629, 0x0804, 0xFE93, 0xFE94, 0xFE94, 0xFE94},
+ {0x062A, 0x0881, 0xFE95, 0xFE96, 0xFE97, 0xFE98},
+ {0x062B, 0x0881, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C},
+ {0x062C, 0x0881, 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0},
+ {0x062D, 0x0881, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4},
+ {0x062E, 0x0881, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8},
+ {0x062F, 0x0804, 0xFEA9, 0xFEAA, 0xFEAA, 0xFEAA},
+ {0x0630, 0x0804, 0xFEAB, 0xFEAC, 0xFEAC, 0xFEAC},
+ {0x0631, 0x0804, 0xFEAD, 0xFEAE, 0xFEAE, 0xFEAE},
+ {0x0632, 0x0804, 0xFEAF, 0xFEB0, 0xFEB0, 0xFEB0},
+ {0x0633, 0x0881, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4},
+ {0x0634, 0x0881, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8},
+ {0x0635, 0x0881, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC},
+ {0x0636, 0x0881, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0},
+ {0x0637, 0x0881, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4},
+ {0x0638, 0x0881, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8},
+ {0x0639, 0x0881, 0xFEC9, 0xFECA, 0xFECB, 0xFECC},
+ {0x063A, 0x0881, 0xFECD, 0xFECE, 0xFECF, 0xFED0},
+ {0x063B, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x063C, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x063D, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x063E, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x063F, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x0640, 0x0888, 0x0640, 0x0640, 0x0640, 0x0640},
+ {0x0641, 0x0881, 0xFED1, 0xFED2, 0xFED3, 0xFED4},
+ {0x0642, 0x0881, 0xFED5, 0xFED6, 0xFED7, 0xFED8},
+ {0x0643, 0x0881, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC},
+ {0x0644, 0x0883, 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0},
+ {0x0645, 0x0881, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4},
+ {0x0646, 0x0881, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8},
+ {0x0647, 0x0881, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC},
+ {0x0648, 0x0804, 0xFEED, 0xFEEE, 0xFEEE, 0xFEEE},
+ {0x0649, 0x0804, 0xFEEF, 0xFEF0, 0xFEF0, 0xFEF0},
+ {0x064A, 0x0881, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4},
+ {0x064B, 0x000C, 0x064B, 0xFE70, 0xFE71, 0xFE70},
+ {0x064C, 0x000C, 0x064C, 0xFE72, 0xFE72, 0xFE72},
+ {0x064D, 0x000C, 0x064D, 0xFE74, 0xFE74, 0xFE74},
+ {0x064E, 0x000A, 0x064E, 0xFE76, 0xFE77, 0xFE76},
+ {0x064F, 0x000A, 0x064F, 0xFE78, 0xFE79, 0xFE78},
+ {0x0650, 0x000A, 0x0650, 0xFE7A, 0xFE7B, 0xFE7A},
+ {0x0651, 0x000A, 0x0651, 0xFE7C, 0xFE7D, 0xFE7C},
+ {0x0652, 0x000A, 0x0652, 0xFE7E, 0xFE7F, 0xFE7E},
+
+ {0x0653, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0654, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0655, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0656, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0657, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0658, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0659, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x065A, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x065B, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x065C, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x065D, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x065E, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x065F, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x0660, 0x000B, 0x0660, 0x0660, 0x0660, 0x0660},
+ {0x0661, 0x000B, 0x0661, 0x0661, 0x0661, 0x0661},
+ {0x0662, 0x000B, 0x0662, 0x0662, 0x0662, 0x0662},
+ {0x0663, 0x000B, 0x0663, 0x0663, 0x0663, 0x0663},
+ {0x0664, 0x000B, 0x0665, 0x0664, 0x0664, 0x0664},
+ {0x0665, 0x000B, 0x0665, 0x0665, 0x0665, 0x0665},
+ {0x0666, 0x000B, 0x0666, 0x0666, 0x0666, 0x0666},
+ {0x0667, 0x000B, 0x0667, 0x0667, 0x0667, 0x0667},
+ {0x0668, 0x000B, 0x0668, 0x0668, 0x0668, 0x0668},
+ {0x0669, 0x000B, 0x0669, 0x0669, 0x0669, 0x0669},
+
+ {0x066A, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x066B, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x066C, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x066D, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x066E, 0x000E, 0x065E, 0x065E, 0x065E, 0x065E},
+ {0x066F, 0x000E, 0x065F, 0x065F, 0x065F, 0x065F},
+
+ {0x0670, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x0671, 0x0804, 0xFB50, 0xFB51, 0xFB51, 0xFB51},
+ {0x0672, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0673, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0674, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0675, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0676, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0677, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0678, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+
+ {0x0679, 0x0881, 0xFB66, 0xFB67, 0xFB68, 0xFB69},
+ {0x067A, 0x0881, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61},
+ {0x067B, 0x0881, 0xFB52, 0xFB53, 0xFB54, 0xFB55},
+ {0x067C, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x067D, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x067E, 0x0881, 0xFB56, 0xFB57, 0xFB58, 0xFB59},
+ {0x067F, 0x0881, 0xFB62, 0xFB63, 0xFB64, 0xFB65},
+ {0x0680, 0x0881, 0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D},
+
+ {0x0681, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0682, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0683, 0x0881, 0xFB76, 0xFB77, 0xFB78, 0xFB79},
+ {0x0684, 0x0881, 0xFB72, 0xFB73, 0xFB74, 0xFB75},
+ {0x0685, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x0686, 0x0881, 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D},
+ {0x0687, 0x0881, 0xFB7E, 0xFB7F, 0xFB80, 0xFB81},
+ {0x0688, 0x0804, 0xFB88, 0xFB89, 0xFB89, 0xFB89},
+ {0x0689, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x068A, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x068B, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x068C, 0x0804, 0xFB84, 0xFB85, 0xFB85, 0xFB85},
+ {0x068D, 0x0804, 0xFB82, 0xFB83, 0xFB83, 0xFB83},
+ {0x068E, 0x0804, 0xFB86, 0xFB87, 0xFB83, 0xFB83},
+ {0x068F, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0690, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x0691, 0x0804, 0xFB8C, 0xFB8D, 0xFB8D, 0xFB8D},
+ {0x0692, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0693, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0694, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0695, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0696, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x0697, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x0698, 0x0804, 0xFB8A, 0xFB8B, 0xFB8B, 0xFB8B},
+ {0x0699, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x069A, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x069B, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x069C, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x069D, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x069E, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x069F, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06A0, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06A1, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06A2, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06A3, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06A4, 0x0881, 0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D},
+ {0x06A5, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06A6, 0x0881, 0xFB6E, 0xFB6F, 0xFB70, 0xFB71},
+ {0x06A7, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06A8, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x06A9, 0x0881, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91},
+ {0x06AA, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06AB, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06AC, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06AD, 0x0881, 0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6},
+ {0x06AE, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x06AF, 0x0881, 0xFB92, 0xFB93, 0xFB94, 0xFB95},
+ {0x06B0, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06B1, 0x0881, 0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D},
+ {0x06B2, 0x000F, 0x0, 0x0, 0x0, 0x0},
+
+ {0x06B3, 0x0881, 0xFB96, 0xFB97, 0xFB98, 0xFB99},
+ {0x06B4, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06B5, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06B6, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06B7, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06B8, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06B9, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06BA, 0x0804, 0xFB9E, 0xFB9F, 0xFB9F, 0xFB9F},
+ {0x06BB, 0x0881, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3},
+ {0x06BC, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06BD, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06BE, 0x0881, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD},
+ {0x06BF, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06C0, 0x0804, 0xFBA4, 0xFBA5, 0xFBA5, 0xFBA5},
+ {0x06C1, 0x0881, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9},
+ {0x06C2, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06C3, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06C4, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06C5, 0x0804, 0xFBE0, 0xFBE1, 0xFBE1, 0xFBE1},
+ {0x06C6, 0x0804, 0xFBD9, 0xFBDA, 0xFBDA, 0xFBDA},
+ {0x06C7, 0x0804, 0xFBD7, 0xFBD8, 0xFBD8, 0xFBD8},
+ {0x06C8, 0x0804, 0xFBDB, 0xFBDC, 0xFBDC, 0xFBDC},
+ {0x06C9, 0x0804, 0xFBE2, 0xFBE3, 0xFBE3, 0xFBE3},
+ {0x06CA, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06CB, 0x0804, 0xFBDE, 0xFBDF, 0xFBDF, 0xFBDF},
+ {0x06CC, 0x0881, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF},
+ {0x06CD, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06CE, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06CF, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06D0, 0x0881, 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7},
+ {0x06D1, 0x000F, 0x0, 0x0, 0x0, 0x0},
+ {0x06D2, 0x0804, 0xFBAE, 0xFBAF, 0xFBAF, 0xFBAF},
+ {0x06D3, 0x0804, 0xFBB0, 0xFBB1, 0xFBB1, 0xFBB1}
+ };
+
+
+ /* @hide*/
+ public static String reshape(String Str){
+ String Temp=" "+Str+" ";
+ char pre,at,post;
+ StringBuilder reshapedString=new StringBuilder() ;
+ int i=0;
+ int len=Str.length();
+
+ char post_post;
+ char pre_pre=' ';
+
+ while (i<len){
+ pre=Temp.charAt(i+2);
+ at=Temp.charAt(i+1);
+ post=Temp.charAt(i);
+
+
+ int which_case=getCase(at);
+ int what_case_post=getCase(post);
+ int what_case_pre=getCase(pre);
+ int what_case_post_post;
+ int what_case_pre_pre;
+ //which_case=0x000F&
+ // Log.v("what case"," :" +which_case);
+ int pre_step=0;
+ if (what_case_pre==TASHKEEL){
+ pre=Temp.charAt(i+3);
+ what_case_pre=getCase(pre);
+ }
+ if ((what_case_pre&LEFT_CHAR_MASK)==LEFT_CHAR_MASK){
+ pre_step=1;
+
+ }
+
+ // System.out.println("##letter "+ pre);
+ switch (which_case&0x000F){
+
+ case NOTUSED_CHAR:
+ case NOTARABIC_CHAR:
+
+ reshapedString.append(at);
+
+ i++;
+ continue;
+ case NORIGHT_NOLEFT_CHAR:
+ case TATWEEL_CHAR:
+ reshapedString.append(getShape(at,0));
+
+ i++;
+ continue;
+ case RIGHT_NOLEFT_CHAR_ALEF:
+
+ // System.out.println("--letter "+ pre);
+
+ if ((what_case_pre&0x000F)==RIGHT_LEFT_CHAR_LAM){
+ pre=Temp.charAt(i+3);
+ // System.out.println("++letter "+ pre);
+ what_case_pre=getCase(pre);
+ pre_step=0;
+ if ((what_case_pre&LEFT_CHAR_MASK)==LEFT_CHAR_MASK){
+ pre_step=1;
+
+ }
+ reshapedString.append(getShape(at,pre_step+2));
+ i=i+2;
+
+ continue;
+ } /*else if ((what_case_post&RIGHT_NOLEFT_CHAR_MASK)==RIGHT_NOLEFT_CHAR_MASK){
+ reshapedString.append(getShape(at,2+pre_step));
+ i=i+1;
+
+ continue;
+
+
+ } else if (what_case_post==TANWEEN){
+ reshapedString.append(getShape(at,pre_step));
+ i=i+1;
+ continue;
+
+
+ } else if (what_case_post==TASHKEEL){
+ post_post=Temp.charAt(i+3);
+ what_case_post_post=getCase(post_post);
+ if ((what_case_post_post&RIGHT_NOLEFT_CHAR_MASK)==RIGHT_NOLEFT_CHAR_MASK){
+ reshapedString.append(getShape(at,2+pre_step));
+ i=i+1;
+
+ continue;
+
+ } else {
+ reshapedString.append(getShape(at,pre_step));
+ i=i+1;
+ continue;
+
+ }
+
+
+
+
+
+ } */else {
+ reshapedString.append(getShape(at,pre_step));
+ i=i+1;
+ continue;
+
+ }
+ case RIGHT_LEFT_CHAR_LAM:
+ case RIGHT_LEFT_CHAR:
+ if ((what_case_post&RIGHT_NOLEFT_CHAR_MASK)==RIGHT_NOLEFT_CHAR_MASK){
+ reshapedString.append(getShape(at,2+pre_step));
+ i=i+1;
+ continue;
+
+
+ } else if (what_case_post==TANWEEN){
+ reshapedString.append(getShape(at,pre_step));
+ i=i+1;
+ continue;
+
+
+ } else if (what_case_post==TASHKEEL){
+ post_post=Temp.charAt(i+3);
+ what_case_post_post=getCase(post_post);
+ if ((what_case_post_post&RIGHT_NOLEFT_CHAR_MASK)==RIGHT_NOLEFT_CHAR_MASK){
+ reshapedString.append(getShape(at,2+pre_step));
+ i=i+1;
+ continue;
+
+ } else {
+ reshapedString.append(getShape(at,pre_step));
+ i=i+1;
+ continue;
+
+ }
+
+
+
+
+
+ } else {
+ reshapedString.append(getShape(at,pre_step));
+ i=i+1;
+ continue;
+
+ }
+
+ case RIGHT_NOLEFT_CHAR:
+ reshapedString.append(getShape(at,pre_step));
+ i=i+1;
+ continue;
+ case TASHKEEL:
+ reshapedString.append(getShape(at,0));
+ i++;
+ pre_pre=pre;
+ continue;
+ case TANWEEN:
+ reshapedString.append(getShape(at,0));
+ i++;
+ pre_pre=pre;
+ continue;
+
+
+
+ default:
+ reshapedString.append(getShape(at,0));
+ i++;
+
+
+ }
+
+
+
+ }
+
+ return reshapedString.toString();
+ }
+
+
+
+
+
+
+
+
+
+
+
+ static int getCase(char ch){
+ if (ch<0x0621 || ch>0x06d2 ){
+ return 0;
+
+
+ }
+ else {
+
+ return allchar[(int)ch-0x0621][1];
+
+ }
+
+
+ }
+
+
+ static char getShape(char ch, int which_shape){
+
+ return allchar[(int)ch-0x0621][2+which_shape];
+
+ }
+
+
+
+
+}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 345f810..266dd58 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -34,7 +34,9 @@ import javax.microedition.khronos.opengles.GL;
public class Canvas {
// assigned in constructors, freed in finalizer
final int mNativeCanvas;
-
+ private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
+ private static final char LAST_RIGHT_TO_LEFT = '\u07b1';
+
/* Our native canvas can be either a raster, gl, or picture canvas.
If we are raster, then mGL will be null, and mBitmap may or may not be
present (our default constructor creates a raster canvas but no
@@ -44,7 +46,7 @@ public class Canvas {
*/
private Bitmap mBitmap; // if not null, mGL must be null
private GL mGL; // if not null, mBitmap must be null
-
+
// optional field set by the caller
private DrawFilter mDrawFilter;
@@ -53,7 +55,7 @@ public class Canvas {
// Used to determine when compatibility scaling is in effect.
private int mScreenDensity = Bitmap.DENSITY_NONE;
-
+
// Used by native code
@SuppressWarnings({"UnusedDeclaration"})
private int mSurfaceFormat;
@@ -72,7 +74,7 @@ public class Canvas {
/**
* Construct a canvas with the specified bitmap to draw into. The bitmap
* must be mutable.
- *
+ *
* <p>The initial target density of the canvas is the same as the given
* bitmap's density.
*
@@ -88,7 +90,7 @@ public class Canvas {
mBitmap = bitmap;
mDensity = bitmap.mDensity;
}
-
+
/*package*/ Canvas(int nativeCanvas) {
if (nativeCanvas == 0) {
throw new IllegalStateException();
@@ -96,14 +98,14 @@ public class Canvas {
mNativeCanvas = nativeCanvas;
mDensity = Bitmap.getDefaultDensity();
}
-
+
/**
* Construct a canvas with the specified gl context. All drawing through
* this canvas will be redirected to OpenGL. Note: some features may not
* be supported in this mode (e.g. some GL implementations may not support
* antialiasing or certain effects like ColorMatrix or certain Xfermodes).
* However, no exception will be thrown in those cases.
- *
+ *
* <p>The initial target density of the canvas is the same as the initial
* density of bitmaps as per {@link Bitmap#getDensity() Bitmap.getDensity()}.
*/
@@ -112,7 +114,7 @@ public class Canvas {
mGL = gl;
mDensity = Bitmap.getDefaultDensity();
}
-
+
/**
* Return the GL object associated with this canvas, or null if it is not
* backed by GL.
@@ -120,7 +122,7 @@ public class Canvas {
public GL getGL() {
return mGL;
}
-
+
/**
* Call this to free up OpenGL resources that may be cached or allocated
* on behalf of the Canvas. Any subsequent drawing with a GL-backed Canvas
@@ -129,13 +131,13 @@ public class Canvas {
public static void freeGlCaches() {
freeCaches();
}
-
+
/**
* Specify a bitmap for the canvas to draw into. As a side-effect, also
* updates the canvas's target density to match that of the bitmap.
*
* @param bitmap Specifies a mutable bitmap for the canvas to draw into.
- *
+ *
* @see #setDensity(int)
* @see #getDensity()
*/
@@ -152,7 +154,7 @@ public class Canvas {
mBitmap = bitmap;
mDensity = bitmap.mDensity;
}
-
+
/**
* Set the viewport dimensions if this canvas is GL based. If it is not,
* this method is ignored and no exception is thrown.
@@ -197,7 +199,7 @@ public class Canvas {
* to determine the scaling factor when drawing a bitmap into it.
*
* @see #setDensity(int)
- * @see Bitmap#getDensity()
+ * @see Bitmap#getDensity()
*/
public int getDensity() {
return mDensity;
@@ -213,7 +215,7 @@ public class Canvas {
* {@link Bitmap#DENSITY_NONE} to disable bitmap scaling.
*
* @see #getDensity()
- * @see Bitmap#setDensity(int)
+ * @see Bitmap#setDensity(int)
*/
public void setDensity(int density) {
if (mBitmap != null) {
@@ -226,7 +228,7 @@ public class Canvas {
public void setScreenDensity(int density) {
mScreenDensity = density;
}
-
+
// the SAVE_FLAG constants must match their native equivalents
/** restore the current matrix when restore() is called */
@@ -240,8 +242,8 @@ public class Canvas {
/** clip against the layer's bounds */
public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
/** restore everything when restore() is called */
- public static final int ALL_SAVE_FLAG = 0x1F;
-
+ public static final int ALL_SAVE_FLAG = 0x1F;
+
/**
* Saves the current matrix and clip onto a private stack. Subsequent
* calls to translate,scale,rotate,skew,concat or clipRect,clipPath
@@ -252,7 +254,7 @@ public class Canvas {
* @return The value to pass to restoreToCount() to balance this save()
*/
public native int save();
-
+
/**
* Based on saveFlags, can save the current matrix and clip onto a private
* stack. Subsequent calls to translate,scale,rotate,skew,concat or
@@ -287,7 +289,7 @@ public class Canvas {
paint != null ? paint.mNativePaint : 0,
saveFlags);
}
-
+
/**
* Helper version of saveLayer() that takes 4 values rather than a RectF.
*/
@@ -318,7 +320,7 @@ public class Canvas {
alpha = Math.min(255, Math.max(0, alpha));
return native_saveLayerAlpha(mNativeCanvas, bounds, alpha, saveFlags);
}
-
+
/**
* Helper for saveLayerAlpha() that takes 4 values instead of a RectF.
*/
@@ -422,7 +424,7 @@ public class Canvas {
public void concat(Matrix matrix) {
native_concat(mNativeCanvas, matrix.native_instance);
}
-
+
/**
* Completely replace the current matrix with the specified matrix. If the
* matrix parameter is null, then the current matrix is reset to identity.
@@ -434,7 +436,7 @@ public class Canvas {
native_setMatrix(mNativeCanvas,
matrix == null ? 0 : matrix.native_instance);
}
-
+
/**
* Return, in ctm, the current transformation matrix. This does not alter
* the matrix in the canvas, but just returns a copy of it.
@@ -442,7 +444,7 @@ public class Canvas {
public void getMatrix(Matrix ctm) {
native_getCTM(mNativeCanvas, ctm.native_instance);
}
-
+
/**
* Return a new matrix with a copy of the canvas' current transformation
* matrix.
@@ -452,7 +454,7 @@ public class Canvas {
getMatrix(m);
return m;
}
-
+
/**
* Modify the current clip with the specified rectangle.
*
@@ -488,7 +490,7 @@ public class Canvas {
* @return true if the resulting clip is non-empty
*/
public native boolean clipRect(RectF rect);
-
+
/**
* Intersect the current clip with the specified rectangle, which is
* expressed in local coordinates.
@@ -497,7 +499,7 @@ public class Canvas {
* @return true if the resulting clip is non-empty
*/
public native boolean clipRect(Rect rect);
-
+
/**
* Modify the current clip with the specified rectangle, which is
* expressed in local coordinates.
@@ -534,7 +536,7 @@ public class Canvas {
*/
public native boolean clipRect(float left, float top,
float right, float bottom);
-
+
/**
* Intersect the current clip with the specified rectangle, which is
* expressed in local coordinates.
@@ -550,7 +552,7 @@ public class Canvas {
*/
public native boolean clipRect(int left, int top,
int right, int bottom);
-
+
/**
* Modify the current clip with the specified path.
*
@@ -561,7 +563,7 @@ public class Canvas {
public boolean clipPath(Path path, Region.Op op) {
return native_clipPath(mNativeCanvas, path.ni(), op.nativeInt);
}
-
+
/**
* Intersect the current clip with the specified path.
*
@@ -571,7 +573,7 @@ public class Canvas {
public boolean clipPath(Path path) {
return clipPath(path, Region.Op.INTERSECT);
}
-
+
/**
* Modify the current clip with the specified region. Note that unlike
* clipRect() and clipPath() which transform their arguments by the
@@ -600,11 +602,11 @@ public class Canvas {
public boolean clipRegion(Region region) {
return clipRegion(region, Region.Op.INTERSECT);
}
-
+
public DrawFilter getDrawFilter() {
return mDrawFilter;
}
-
+
public void setDrawFilter(DrawFilter filter) {
int nativeFilter = 0;
if (filter != null) {
@@ -617,7 +619,7 @@ public class Canvas {
public enum EdgeType {
BW(0), //!< treat edges by just rounding to nearest pixel boundary
AA(1); //!< treat edges by rounding-out, since they may be antialiased
-
+
EdgeType(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -695,7 +697,7 @@ public class Canvas {
public boolean getClipBounds(Rect bounds) {
return native_getClipBounds(mNativeCanvas, bounds);
}
-
+
/**
* Retrieve the clip bounds.
*
@@ -706,7 +708,7 @@ public class Canvas {
getClipBounds(r);
return r;
}
-
+
/**
* Fill the entire canvas' bitmap (restricted to the current clip) with the
* specified RGB color, using srcover porterduff mode.
@@ -763,7 +765,7 @@ public class Canvas {
public void drawPaint(Paint paint) {
native_drawPaint(mNativeCanvas, paint.mNativePaint);
}
-
+
/**
* Draw a series of points. Each point is centered at the coordinate
* specified by pts[], and its diameter is specified by the paint's stroke
@@ -853,7 +855,7 @@ public class Canvas {
public void drawRect(Rect r, Paint paint) {
drawRect(r.left, r.top, r.right, r.bottom, paint);
}
-
+
/**
* Draw the specified Rect using the specified paint. The rectangle will
@@ -949,7 +951,7 @@ public class Canvas {
public void drawPath(Path path, Paint paint) {
native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint);
}
-
+
private static void throwIfRecycled(Bitmap bitmap) {
if (bitmap.isRecycled()) {
throw new RuntimeException(
@@ -960,7 +962,7 @@ public class Canvas {
/**
* Draw the specified bitmap, with its top/left corner at (x,y), using
* the specified paint, transformed by the current matrix.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -970,7 +972,7 @@ public class Canvas {
* <p>If the bitmap and canvas have different densities, this function
* will take care of automatically scaling the bitmap to draw at the
* same density as the canvas.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param left The position of the left side of the bitmap being drawn
* @param top The position of the top side of the bitmap being drawn
@@ -987,7 +989,7 @@ public class Canvas {
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -998,7 +1000,7 @@ public class Canvas {
* This is because the source and destination rectangle coordinate
* spaces are in their respective densities, so must already have the
* appropriate scaling factor applied.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
@@ -1019,7 +1021,7 @@ public class Canvas {
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1030,7 +1032,7 @@ public class Canvas {
* This is because the source and destination rectangle coordinate
* spaces are in their respective densities, so must already have the
* appropriate scaling factor applied.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
@@ -1046,7 +1048,7 @@ public class Canvas {
paint != null ? paint.mNativePaint : 0,
mScreenDensity, bitmap.mDensity);
}
-
+
/**
* Treat the specified array of colors as a bitmap, and draw it. This gives
* the same result as first creating a bitmap from the array, and then
@@ -1093,7 +1095,7 @@ public class Canvas {
native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, width, height, hasAlpha,
paint != null ? paint.mNativePaint : 0);
}
-
+
/** Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y
*/
public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
@@ -1103,7 +1105,7 @@ public class Canvas {
drawBitmap(colors, offset, stride, (float)x, (float)y, width, height,
hasAlpha, paint);
}
-
+
/**
* Draw the bitmap using the specified matrix.
*
@@ -1115,13 +1117,13 @@ public class Canvas {
nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(),
paint != null ? paint.mNativePaint : 0);
}
-
+
private static void checkRange(int length, int offset, int count) {
if ((offset | count) < 0 || offset + count > length) {
throw new ArrayIndexOutOfBoundsException();
}
}
-
+
/**
* Draw the bitmap through the mesh, where mesh vertices are evenly
* distributed across the bitmap. There are meshWidth+1 vertices across, and
@@ -1168,18 +1170,18 @@ public class Canvas {
verts, vertOffset, colors, colorOffset,
paint != null ? paint.mNativePaint : 0);
}
-
+
public enum VertexMode {
TRIANGLES(0),
TRIANGLE_STRIP(1),
TRIANGLE_FAN(2);
-
+
VertexMode(int nativeInt) {
this.nativeInt = nativeInt;
}
final int nativeInt;
}
-
+
/**
* Draw the array of vertices, interpreted as triangles (based on mode). The
* verts array is required, and specifies the x,y pairs for each vertex. If
@@ -1208,7 +1210,7 @@ public class Canvas {
* @param indices If not null, array of indices to reference into the
* vertex (texs, colors) array.
* @param indexCount number of entries in the indices array (if not null).
- * @param paint Specifies the shader to use if the texs array is non-null.
+ * @param paint Specifies the shader to use if the texs array is non-null.
*/
public void drawVertices(VertexMode mode, int vertexCount,
float[] verts, int vertOffset,
@@ -1230,7 +1232,169 @@ public class Canvas {
vertOffset, texs, texOffset, colors, colorOffset,
indices, indexOffset, indexCount, paint.mNativePaint);
}
-
+
+ /**
+ * Since the reshaping algorithm does not test for arabic prior to starting, this is made to
+ * @hide
+ **/
+ public static boolean bidiTest(char[] text,int start,int srcCount) {
+
+ boolean hasBidi=false;
+
+ // Check if there are BiDi characters in the string, of so, we need to work.
+ for (int i=start;i<(srcCount+start);i++){
+ if (text[i]>=FIRST_RIGHT_TO_LEFT&&text[i]<=LAST_RIGHT_TO_LEFT){
+ hasBidi=true;
+ break;
+ }
+ }
+ return hasBidi;
+ }
+ /**
+ * Since the reshaping algorithm does not test for arabic prior to starting, this is made to
+ * @hide
+ **/
+ public static boolean bidiTest(String text,int start,int srcCount) {
+
+ boolean hasBidi=false;
+
+ // Check if there are BiDi characters in the string, of so, we need to work.
+ for (int i=start;i<(srcCount+start);i++){
+ if (text.charAt(i)>=FIRST_RIGHT_TO_LEFT&&text.charAt(i)<=LAST_RIGHT_TO_LEFT){
+ hasBidi=true;
+ break;
+ }
+ }
+ return hasBidi;
+ }
+ /**
+ * A lightweight BiDi processing to make all draw text work with RTL languages.
+ * written from scratch by David Kohen (kohen dot d at gmail dot com) - 2010
+ * @hide
+ **/
+ public static char[] bidiProcess(char[] text,int start,int srcCount) {
+
+ boolean hasBidi=false;
+ char[] destCharArray=new char[srcCount];
+
+ char[] buf = TemporaryBuffer.obtain(srcCount);
+ System.arraycopy(text,start, buf, 0, srcCount);
+
+ // I'm doing the processing from the end of the string, since it worked well this way.
+ int count=0,srcIndex=0;
+ boolean rtlMode=true;
+ for (int i=0;i<srcCount;i++){
+ srcIndex=srcCount-1-i;
+ if (buf[srcIndex]>=FIRST_RIGHT_TO_LEFT&&buf[srcIndex]<=LAST_RIGHT_TO_LEFT){
+ destCharArray[i]=buf[srcIndex];
+ // In rtl mode I'm mirroring glyphs.
+ rtlMode=true;
+ }
+ else {
+ srcIndex=srcCount-1-i;
+ if (count==0) {
+ // Direction neutral characters
+ if (buf[srcIndex]<='\u002f' ||
+ (buf[srcIndex]>'\u0039' && buf[srcIndex]<='\u0040') ||
+ (buf[srcIndex]>'\u005a' && buf[srcIndex]<='\u0060')||
+ (buf[srcIndex]>'\u007a' && buf[srcIndex]<='\u00BF')) {
+
+ if (rtlMode){
+ switch (buf[srcIndex]) {
+ case '[':
+ destCharArray[i]=']';
+ break;
+ case ']':
+ destCharArray[i]='[';
+ break;
+ case '}':
+ destCharArray[i]='{';
+ break;
+ case '{':
+ destCharArray[i]='}';
+ break;
+ case '(':
+ destCharArray[i]=')';
+ break;
+ case ')':
+ destCharArray[i]='(';
+ break;
+ case '>':
+ destCharArray[i]='<';
+ break;
+ case '<':
+ destCharArray[i]='>';
+ break;
+ default:
+ destCharArray[i]=buf[srcIndex];
+ break;
+ }
+ } else destCharArray[i]=buf[srcIndex];
+ } else {
+ // Handling LTR embedded strings.
+ while (((srcIndex-count)>=0)&&((buf[srcIndex-count]<FIRST_RIGHT_TO_LEFT)||(buf[srcIndex-count]>LAST_RIGHT_TO_LEFT))){
+ count++;
+ }
+ int index=0;
+ int punctuationMarks=0;
+
+ // Handling direction neutral characters in the middle of LTR
+ while (count>0 && (srcIndex-(count)>=0) &&
+ (buf[srcIndex-(count-1)]<='\u002f' ||
+ (buf[srcIndex-(count-1)]>'\u0039' && buf[srcIndex-(count-1)]<='\u0040') ||
+ (buf[srcIndex-(count-1)]>'\u005a' && buf[srcIndex-(count-1)]<='\u0060')||
+ (buf[srcIndex-(count-1)]>'\u007a' && buf[srcIndex-(count-1)]<='\u00BF'))){
+ destCharArray[i+(count-1)]=buf[srcIndex-(count-1)];
+ count--;
+ punctuationMarks++;
+ }
+
+ while (count>0){
+ destCharArray[i+index]=buf[srcIndex-(count-1)];
+ count--;
+ index++;
+ }
+ count=index+punctuationMarks-1;
+ }
+ }
+ else {
+ // Avoiding spaghetti code and mangling of loop counter
+ count--;
+ }
+ rtlMode=false;
+ }
+ }
+ return destCharArray;
+ }
+
+ /** @hide **/
+ public void drawText(char[] text, int index, int count, float x, float y,
+ Paint paint,boolean bidi) {
+ if (((index | count | (index + count)) < 0) ||
+ (index + count) > text.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ boolean hasBidi=bidiTest(text,index,count);
+ if (hasBidi) {
+ if (bidi) {
+ char[] bidiText=bidiProcess(text,index,count);
+ String reshapedText=ArabicReshape.reshape(new String(bidiText));
+ /* The reshaping may make the string smaller */
+ native_drawText(mNativeCanvas, reshapedText.toCharArray(), 0, count - ((count - reshapedText.length())>0 ? (count - reshapedText.length()) : 0), x, y,
+ paint.mNativePaint);
+ } else {
+ String reshapedText=ArabicReshape.reshape(new String(text));
+ /* The reshaping may make the string smaller */
+ native_drawText(mNativeCanvas, reshapedText.toCharArray(), index,
+ count - ((text.length - reshapedText.length())>0 ? (text.length - reshapedText.length()) : 0), x, y,
+ paint.mNativePaint);
+ }
+ } else {
+ native_drawText(mNativeCanvas, text, index, count, x, y,
+ paint.mNativePaint);
+ }
+ }
+
/**
* Draw the text, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
@@ -1246,8 +1410,14 @@ public class Canvas {
(text.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_drawText(mNativeCanvas, text, index, count, x, y,
- paint.mNativePaint);
+
+ boolean hasBidi=bidiTest(text,index,count);
+ if (hasBidi) {
+ drawText(text,index,count,x,y,paint,true);
+ } else {
+ native_drawText(mNativeCanvas, text, index, count, x, y,
+ paint.mNativePaint);
+ }
}
/**
@@ -1259,7 +1429,28 @@ public class Canvas {
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public native void drawText(String text, float x, float y, Paint paint);
+ private native void native_drawText(String text, float x, float y, Paint paint);
+
+ /** @hide */
+ public void drawText(String text, float x, float y, Paint paint,boolean bidi){
+ boolean hasBidi=bidiTest(text,0,text.length());
+ if (hasBidi) {
+ if (!bidi) {
+ native_drawText(ArabicReshape.reshape(text),x,y,paint);
+ } else {
+ if (text.length() > 0) {
+ String bidiText;
+ bidiText=new String(bidiProcess(text.toCharArray(),0,text.length()));
+ native_drawText(ArabicReshape.reshape(bidiText),x,y,paint);
+ }
+ }
+ } else {
+ native_drawText(text,x,y,paint);
+ }
+ }
+ public void drawText(String text, float x, float y, Paint paint){
+ drawText(text,x,y,paint,true);
+ }
/**
* Draw the text, with origin at (x,y), using the specified paint.
@@ -1277,8 +1468,16 @@ public class Canvas {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_drawText(mNativeCanvas, text, start, end, x, y,
- paint.mNativePaint);
+ boolean hasBidi=bidiTest(text,start,end-start);
+ if (hasBidi) {
+ String reshapedText=ArabicReshape.reshape(new String(bidiProcess(text.toCharArray(),start,end-start)));
+ /* The reshaping may make the string smaller */
+ native_drawText(mNativeCanvas, reshapedText, 0, end-start - ((end-start - reshapedText.length())>0?(end-start - reshapedText.length()):0), x, y,
+ paint.mNativePaint);
+ } else {
+ native_drawText(mNativeCanvas, text, start, end, x, y,
+ paint.mNativePaint);
+ }
}
/**
@@ -1296,21 +1495,49 @@ public class Canvas {
*/
public void drawText(CharSequence text, int start, int end, float x,
float y, Paint paint) {
+ drawText(text,start,end,x,y,paint,true);
+ }
+
+ /** @hide */
+ public void drawText(CharSequence text, int start, int end, float x,
+ float y, Paint paint,boolean bidi) {
+ boolean hasBidi=bidiTest(text.toString(),start,end-start);
if (text instanceof String || text instanceof SpannedString ||
- text instanceof SpannableString) {
- native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
+ text instanceof SpannableString) {
+ if (hasBidi) {
+ if (bidi) {
+ String bidiText=new String(bidiProcess(text.toString().toCharArray(),start,end-start));
+ String reshapedText=ArabicReshape.reshape(bidiText);
+ /* The reshaping may make the string smaller */
+ native_drawText(mNativeCanvas, reshapedText, 0, (end-start) - ((end-start - reshapedText.length())>0 ? (end-start - reshapedText.length()) : 0), x, y,
+ paint.mNativePaint);
+ } else {
+ String reshapedText=ArabicReshape.reshape(text.toString());
+ /* The reshaping may make the string smaller */
+ native_drawText(mNativeCanvas, reshapedText, 0, (end-start) - ((end-start - reshapedText.length())>0 ? (end-start - reshapedText.length()) : 0), x, y,
+ paint.mNativePaint);
+ }
+ } else {
+ native_drawText(mNativeCanvas, text.toString() , start, end, x, y,
paint.mNativePaint);
+ }
}
else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
- paint);
- }
- else {
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- drawText(buf, 0, end - start, x, y, paint);
- TemporaryBuffer.recycle(buf);
- }
+ paint);
+ }
+ else {
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ TextUtils.getChars(text, start, end, buf, 0);
+ if (hasBidi) {
+ String reshapedText=ArabicReshape.reshape(new String(buf));
+ /* The reshaping may make the string smaller */
+ drawText(reshapedText.toCharArray(), 0, (end - start) - (((end - start) - reshapedText.length())>0?((end - start) - reshapedText.length()):0), x, y, paint,false);
+ } else {
+ drawText(buf, 0, end - start, x, y, paint,false);
+ }
+ TemporaryBuffer.recycle(buf);
+ }
}
/**
@@ -1326,11 +1553,24 @@ public class Canvas {
*/
public void drawPosText(char[] text, int index, int count, float[] pos,
Paint paint) {
- if (index < 0 || index + count > text.length || count*2 > pos.length) {
+ if (index < 0 || index + count > text.length || (index+count)*2 > pos.length) {
throw new IndexOutOfBoundsException();
}
- native_drawPosText(mNativeCanvas, text, index, count, pos,
- paint.mNativePaint);
+
+ boolean hasBidi=bidiTest(text,index,count);
+ if (hasBidi) {
+ float[] relativePos = new float[count*2];
+ System.arraycopy(pos , index*2 , relativePos , 0, count*2);
+ char[] bidiText;
+ bidiText=bidiProcess(text,index,count);
+ String reshapedText=ArabicReshape.reshape(new String(bidiText));
+ /* The reshaping may make the string smaller */
+ native_drawPosText(mNativeCanvas, reshapedText.toCharArray(), 0, count - ((count - reshapedText.length())>0 ? (count - reshapedText.length()) : 0), relativePos,
+ paint.mNativePaint);
+ } else {
+ native_drawPosText(mNativeCanvas, text, index, count, pos,
+ paint.mNativePaint);
+ }
}
/**
@@ -1345,7 +1585,16 @@ public class Canvas {
if (text.length()*2 > pos.length) {
throw new ArrayIndexOutOfBoundsException();
}
- native_drawPosText(mNativeCanvas, text, pos, paint.mNativePaint);
+
+ boolean hasBidi=bidiTest(text,0,text.length());
+ if (hasBidi) {
+ String bidiText;
+ bidiText=new String(bidiProcess(text.toCharArray(),0,text.length()));
+ native_drawPosText(mNativeCanvas, ArabicReshape.reshape(bidiText), pos, paint.mNativePaint);
+ } else {
+ native_drawPosText(mNativeCanvas, text, pos,
+ paint.mNativePaint);
+ }
}
/**
@@ -1366,9 +1615,21 @@ public class Canvas {
if (index < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
- native_drawTextOnPath(mNativeCanvas, text, index, count,
- path.ni(), hOffset, vOffset,
- paint.mNativePaint);
+ boolean hasBidi=bidiTest(text,index,count);
+ if (hasBidi) {
+ char[] bidiText;
+ bidiText=bidiProcess(text,index,count);
+ String reshapedText=ArabicReshape.reshape(new String(bidiText));
+ /* The reshaping may make the string smaller */
+ native_drawTextOnPath(mNativeCanvas, reshapedText.toCharArray(), 0, count - ((count - reshapedText.length())>0 ? (count - reshapedText.length()) : 0),
+ path.ni(), hOffset, vOffset,
+ paint.mNativePaint);
+ } else {
+ native_drawTextOnPath(mNativeCanvas, text, index, count,
+ path.ni(), hOffset, vOffset,
+ paint.mNativePaint);
+ }
+ // TODO: Handle index>0
}
/**
@@ -1387,8 +1648,17 @@ public class Canvas {
public void drawTextOnPath(String text, Path path, float hOffset,
float vOffset, Paint paint) {
if (text.length() > 0) {
- native_drawTextOnPath(mNativeCanvas, text, path.ni(),
- hOffset, vOffset, paint.mNativePaint);
+ boolean hasBidi=bidiTest(text,0,text.length());
+ if (hasBidi) {
+ String bidiText;
+ bidiText=new String(bidiProcess(text.toCharArray(),0,text.length()));
+ native_drawTextOnPath(mNativeCanvas, ArabicReshape.reshape(bidiText), path.ni(),
+ hOffset, vOffset, paint.mNativePaint);
+ } else {
+ native_drawTextOnPath(mNativeCanvas, text,
+ path.ni(), hOffset, vOffset,
+ paint.mNativePaint);
+ }
}
}
@@ -1396,14 +1666,14 @@ public class Canvas {
* Save the canvas state, draw the picture, and restore the canvas state.
* This differs from picture.draw(canvas), which does not perform any
* save/restore.
- *
+ *
* @param picture The picture to be drawn
*/
public void drawPicture(Picture picture) {
picture.endRecording();
native_drawPicture(mNativeCanvas, picture.ni());
}
-
+
/**
* Draw the picture, stretched to fit into the dst rectangle.
*/
@@ -1417,7 +1687,7 @@ public class Canvas {
drawPicture(picture);
restore();
}
-
+
/**
* Draw the picture, stretched to fit into the dst rectangle.
*/
@@ -1431,7 +1701,7 @@ public class Canvas {
drawPicture(picture);
restore();
}
-
+
protected void finalize() throws Throwable {
super.finalize();
// If the constructor threw an exception before setting mNativeCanvas, the native finalizer
@@ -1552,7 +1822,7 @@ public class Canvas {
float[] verts, int vertOffset, float[] texs, int texOffset,
int[] colors, int colorOffset, short[] indices,
int indexOffset, int indexCount, int nPaint);
-
+
private static native void native_drawText(int nativeCanvas, char[] text,
int index, int count, float x,
float y, int paint);
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 5cefaa3..26aecba 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -202,7 +202,7 @@ public class Color {
* 'yellow', 'lightgray', 'darkgray'
*/
public static int parseColor(String colorString) {
- if (colorString.charAt(0) == '#') {
+ if (colorString.startsWith("#")) {
// Use a long to avoid rollovers on #ffXXXXXX
long color = Long.parseLong(colorString.substring(1), 16);
if (colorString.length() == 7) {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3e3f87b..5fce6de 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1299,7 +1299,18 @@ public class Paint {
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
- native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
+ boolean hasBidi=Canvas.bidiTest(text,index,count);
+ if (hasBidi) {
+ char[] bidiText;
+ bidiText=Canvas.bidiProcess(text,index,count);
+ String reshapedText=ArabicReshape.reshape(new String(bidiText));
+ /* The reshaping may make the string smaller */
+ native_getTextPath(mNativePaint, reshapedText.toCharArray(), 0,
+ count - ((count-reshapedText.length())>0 ? (count-reshapedText.length()) : 0),
+ x, y, path.ni());
+ } else {
+ native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
+ }
}
/**
@@ -1320,7 +1331,17 @@ public class Paint {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_getTextPath(mNativePaint, text, start, end, x, y, path.ni());
+ boolean hasBidi=Canvas.bidiTest(text,start,start+end);
+ if (hasBidi) {
+ char[] bidiText;
+ bidiText=Canvas.bidiProcess(text.toCharArray(),start,start+end);
+ String reshapedText=ArabicReshape.reshape(String.valueOf(bidiText));
+ /* The reshaping may make the string smaller */
+ native_getTextPath(mNativePaint, reshapedText, 0, end-start - ((end-start - reshapedText.length())>0 ? (end-start - reshapedText.length()) : 0),
+ x, y, path.ni());
+ } else {
+ native_getTextPath(mNativePaint, text, start, end, x, y, path.ni());
+ }
}
/**
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
index 8476be1..13ee169 100644
--- a/graphics/jni/Android.mk
+++ b/graphics/jni/Android.mk
@@ -19,8 +19,12 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libskia \
libutils \
- libui \
- libsurfaceflinger_client
+ libui
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client
+endif
LOCAL_STATIC_LIBRARIES :=
diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h
index 170f20d..2512c27 100644
--- a/include/binder/MemoryDealer.h
+++ b/include/binder/MemoryDealer.h
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#ifdef USE_ECLAIR_MEMORYDEALER
+#include <binder/MemoryDealerEclair.h>
+#else
+
#ifndef ANDROID_MEMORY_DEALER_H
#define ANDROID_MEMORY_DEALER_H
@@ -58,3 +62,4 @@ private:
}; // namespace android
#endif // ANDROID_MEMORY_DEALER_H
+#endif // USE_ECLAIR_MEMORYDEALER
diff --git a/include/binder/MemoryDealerEclair.h b/include/binder/MemoryDealerEclair.h
new file mode 100644
index 0000000..03ac70a
--- /dev/null
+++ b/include/binder/MemoryDealerEclair.h
@@ -0,0 +1,257 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_DEALER_H
+#define ANDROID_MEMORY_DEALER_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IMemory.h>
+#include <utils/threads.h>
+#include <binder/MemoryHeapBase.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+class String8;
+
+/*
+ * interface for implementing a "heap". A heap basically provides
+ * the IMemoryHeap interface for cross-process sharing and the
+ * ability to map/unmap pages within the heap.
+ */
+class HeapInterface : public virtual BnMemoryHeap
+{
+public:
+ // all values must be page-aligned
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
+
+ HeapInterface();
+protected:
+ virtual ~HeapInterface();
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * interface for implementing an allocator. An allocator provides
+ * methods for allocating and freeing memory blocks and dumping
+ * its state.
+ */
+class AllocatorInterface : public RefBase
+{
+public:
+ enum {
+ PAGE_ALIGNED = 0x00000001
+ };
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0) = 0;
+ virtual status_t deallocate(size_t offset) = 0;
+ virtual size_t size() const = 0;
+ virtual void dump(const char* what, uint32_t flags = 0) const = 0;
+ virtual void dump(String8& res,
+ const char* what, uint32_t flags = 0) const = 0;
+
+ AllocatorInterface();
+protected:
+ virtual ~AllocatorInterface();
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * concrete implementation of HeapInterface on top of mmap()
+ */
+class SharedHeap : public HeapInterface, public MemoryHeapBase
+{
+public:
+ SharedHeap();
+ SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
+ virtual ~SharedHeap();
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * A simple templatized doubly linked-list implementation
+ */
+
+template <typename NODE>
+class LinkedList
+{
+ NODE* mFirst;
+ NODE* mLast;
+
+public:
+ LinkedList() : mFirst(0), mLast(0) { }
+ bool isEmpty() const { return mFirst == 0; }
+ NODE const* head() const { return mFirst; }
+ NODE* head() { return mFirst; }
+ NODE const* tail() const { return mLast; }
+ NODE* tail() { return mLast; }
+
+ void insertAfter(NODE* node, NODE* newNode) {
+ newNode->prev = node;
+ newNode->next = node->next;
+ if (node->next == 0) mLast = newNode;
+ else node->next->prev = newNode;
+ node->next = newNode;
+ }
+
+ void insertBefore(NODE* node, NODE* newNode) {
+ newNode->prev = node->prev;
+ newNode->next = node;
+ if (node->prev == 0) mFirst = newNode;
+ else node->prev->next = newNode;
+ node->prev = newNode;
+ }
+
+ void insertHead(NODE* newNode) {
+ if (mFirst == 0) {
+ mFirst = mLast = newNode;
+ newNode->prev = newNode->next = 0;
+ } else {
+ newNode->prev = 0;
+ newNode->next = mFirst;
+ mFirst->prev = newNode;
+ mFirst = newNode;
+ }
+ }
+
+ void insertTail(NODE* newNode) {
+ if (mLast == 0) {
+ insertHead(newNode);
+ } else {
+ newNode->prev = mLast;
+ newNode->next = 0;
+ mLast->next = newNode;
+ mLast = newNode;
+ }
+ }
+
+ NODE* remove(NODE* node) {
+ if (node->prev == 0) mFirst = node->next;
+ else node->prev->next = node->next;
+ if (node->next == 0) mLast = node->prev;
+ else node->next->prev = node->prev;
+ return node;
+ }
+};
+
+
+/*
+ * concrete implementation of AllocatorInterface using a simple
+ * best-fit allocation scheme
+ */
+class SimpleBestFitAllocator : public AllocatorInterface
+{
+public:
+
+ SimpleBestFitAllocator(size_t size);
+ virtual ~SimpleBestFitAllocator();
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0);
+ virtual status_t deallocate(size_t offset);
+ virtual size_t size() const;
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+ virtual void dump(String8& res,
+ const char* what, uint32_t flags = 0) const;
+
+private:
+
+ struct chunk_t {
+ chunk_t(size_t start, size_t size)
+ : start(start), size(size), free(1), prev(0), next(0) {
+ }
+ size_t start;
+ size_t size : 28;
+ int free : 4;
+ mutable chunk_t* prev;
+ mutable chunk_t* next;
+ };
+
+ ssize_t alloc(size_t size, uint32_t flags);
+ chunk_t* dealloc(size_t start);
+ void dump_l(const char* what, uint32_t flags = 0) const;
+ void dump_l(String8& res, const char* what, uint32_t flags = 0) const;
+
+ static const int kMemoryAlign;
+ mutable Mutex mLock;
+ LinkedList<chunk_t> mList;
+ size_t mHeapSize;
+};
+
+// ----------------------------------------------------------------------------
+
+class MemoryDealer : public RefBase
+{
+public:
+
+ enum {
+ READ_ONLY = MemoryHeapBase::READ_ONLY,
+ PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
+ };
+
+ // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
+ MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
+
+ // provide a custom heap but use the SimpleBestFitAllocator
+ MemoryDealer(const sp<HeapInterface>& heap);
+
+ // provide both custom heap and allocotar
+ MemoryDealer(
+ const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator);
+
+ virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
+ virtual void deallocate(size_t offset);
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+
+
+ sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
+ sp<AllocatorInterface> getAllocator() const { return allocator(); }
+
+protected:
+ virtual ~MemoryDealer();
+
+private:
+ const sp<HeapInterface>& heap() const;
+ const sp<AllocatorInterface>& allocator() const;
+
+ class Allocation : public BnMemory {
+ public:
+ Allocation(const sp<MemoryDealer>& dealer,
+ ssize_t offset, size_t size, const sp<IMemory>& memory);
+ virtual ~Allocation();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+ private:
+ sp<MemoryDealer> mDealer;
+ ssize_t mOffset;
+ size_t mSize;
+ sp<IMemory> mMemory;
+ };
+
+ sp<HeapInterface> mHeap;
+ sp<AllocatorInterface> mAllocator;
+};
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_DEALER_H
diff --git a/include/binder/MemoryHeapPmem.h b/include/binder/MemoryHeapPmem.h
index e1660c4..02e83f8 100644
--- a/include/binder/MemoryHeapPmem.h
+++ b/include/binder/MemoryHeapPmem.h
@@ -20,18 +20,26 @@
#include <stdlib.h>
#include <stdint.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
+#include <binder/MemoryDealer.h>
+#endif
#include <binder/MemoryHeapBase.h>
#include <binder/IMemory.h>
#include <utils/SortedVector.h>
+#ifndef USE_ECLAIR_MEMORYDEALER
#include <utils/threads.h>
+#endif
namespace android {
class MemoryHeapBase;
// ---------------------------------------------------------------------------
-
+#ifdef USE_ECLAIR_MEMORYDEALER
+class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
+#else
class MemoryHeapPmem : public MemoryHeapBase
+#endif
{
public:
class MemoryPmem : public BnMemory {
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 5ea83a5..dde56a9 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -25,6 +25,12 @@ namespace android {
class CameraParameters
{
public:
+ enum {
+ CAMERA_ORIENTATION_UNKNOWN = 0,
+ CAMERA_ORIENTATION_PORTRAIT = 1,
+ CAMERA_ORIENTATION_LANDSCAPE = 2,
+ };
+
CameraParameters();
CameraParameters(const String8 &params) { unflatten(params); }
~CameraParameters();
@@ -52,6 +58,9 @@ public:
void setPictureFormat(const char *format);
const char *getPictureFormat() const;
+ int getOrientation() const;
+ void setOrientation(int orientation);
+
void dump() const;
status_t dump(int fd, const Vector<String16>& args) const;
@@ -95,6 +104,10 @@ public:
// The height (in pixels) of EXIF thumbnail in Jpeg picture.
// Example value: "384". Read/write.
static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
+
+ //++TODO is the following parameter is needed when jpeg thumbnail is available
+ static const char KEY_SUPPORTED_THUMBNAIL_SIZES[];
+
// Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail
// in EXIF.
// Example value: "512x384,320x240,0x0". Read only.
@@ -128,6 +141,33 @@ public:
// GPS altitude. This will be stored in JPEG EXIF header.
// Example value: "21.0". Write only.
static const char KEY_GPS_ALTITUDE[];
+
+ static const char KEY_GPS_LATITUDE_REF[];
+ static const char KEY_GPS_LONGITUDE_REF[];
+ static const char KEY_GPS_ALTITUDE_REF[];
+ static const char KEY_GPS_STATUS[];
+ static const char KEY_EXIF_DATETIME[];
+
+ static const char KEY_AUTO_EXPOSURE[];
+ static const char KEY_SUPPORTED_AUTO_EXPOSURE[];
+ static const char KEY_ISO_MODE[];
+ static const char KEY_SUPPORTED_ISO_MODES[];
+ static const char KEY_LENSSHADE[] ;
+ static const char KEY_SUPPORTED_LENSSHADE_MODES[] ;
+ static const char KEY_SHARPNESS[];
+ static const char KEY_MAX_SHARPNESS[];
+ static const char KEY_CONTRAST[];
+ static const char KEY_MAX_CONTRAST[];
+ static const char KEY_SATURATION[];
+ static const char KEY_MAX_SATURATION[];
+
+ // Values for auto exposure settings.
+ static const char AUTO_EXPOSURE_FRAME_AVG[];
+ static const char AUTO_EXPOSURE_CENTER_WEIGHTED[];
+ static const char AUTO_EXPOSURE_SPOT_METERING[];
+
+
+
// GPS timestamp (UTC in seconds since January 1, 1970). This should be
// stored in JPEG EXIF header.
// Example value: "1251192757". Write only.
@@ -292,6 +332,7 @@ public:
static const char PIXEL_FORMAT_YUV422I[]; // YUY2
static const char PIXEL_FORMAT_RGB565[];
static const char PIXEL_FORMAT_JPEG[];
+ static const char PIXEL_FORMAT_RAW[];
// Values for focus mode settings.
// Auto-focus mode.
@@ -299,6 +340,7 @@ public:
// Focus is set at infinity. Applications should not call
// CameraHardwareInterface.autoFocus in this mode.
static const char FOCUS_MODE_INFINITY[];
+ static const char FOCUS_MODE_NORMAL[];
static const char FOCUS_MODE_MACRO[];
// Focus is fixed. The camera is always in this mode if the focus is not
// adjustable. If the camera has auto-focus, this mode can fix the
@@ -310,6 +352,16 @@ public:
// CameraHardwareInterface.autoFocus in this mode.
static const char FOCUS_MODE_EDOF[];
+ static const char ISO_AUTO[];
+ static const char ISO_HJR[] ;
+ static const char ISO_100[];
+ static const char ISO_200[] ;
+ static const char ISO_400[];
+ static const char ISO_800[];
+ static const char ISO_1600[];
+ // Values for Lens Shading
+ static const char LENSSHADE_ENABLE[] ;
+ static const char LENSSHADE_DISABLE[] ;
private:
DefaultKeyedVector<String8,String8> mMap;
};
@@ -317,3 +369,4 @@ private:
}; // namespace android
#endif
+
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 92bc126..18347d5 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -129,9 +129,9 @@ public:
*/
enum record_flags {
- RECORD_AGC_ENABLE = AudioSystem::AGC_ENABLE,
- RECORD_NS_ENABLE = AudioSystem::NS_ENABLE,
- RECORD_IIR_ENABLE = AudioSystem::TX_IIR_ENABLE
+ RECORD_AGC_ENABLE = 0x0001, // AudioSystem::AGC_ENABLE,
+ RECORD_NS_ENABLE = 0x0002, // AudioSystem::NS_ENABLE,
+ RECORD_IIR_ENABLE = 0x0004, // AudioSystem::TX_IIR_ENABLE
};
AudioRecord(int inputSource,
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 73bf2ee..769d914 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -43,6 +43,7 @@ public:
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
virtual status_t setParameters(const String8& params) = 0;
+ virtual status_t setCameraParameters(const String8& params) = 0;
virtual status_t setListener(const sp<IMediaPlayerClient>& listener) = 0;
virtual status_t prepare() = 0;
virtual status_t getMaxAmplitude(int* max) = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 9e606d9..a50ce35 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -45,6 +45,7 @@ enum player_type {
// The shared library with the test player is passed passed as an
// argument to the 'test:' url in the setDataSource call.
TEST_PLAYER = 5,
+ FLAC_PLAYER = 6,
};
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index a4eea2a..5354937 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -24,8 +24,9 @@
namespace android {
enum camcorder_quality {
- CAMCORDER_QUALITY_LOW = 0,
- CAMCORDER_QUALITY_HIGH = 1
+ CAMCORDER_QUALITY_LOW = 0,
+ CAMCORDER_QUALITY_HIGH = 1,
+ CAMCORDER_QUALITY_FRONT = 2
};
enum video_decoder {
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 5b787a7..c16daa8 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -41,6 +41,7 @@ struct MediaRecorderBase {
virtual status_t setOutputFile(const char *path) = 0;
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setParameters(const String8& params) = 0;
+ virtual status_t setCameraParameters(const String8& params) = 0;
virtual status_t setListener(const sp<IMediaPlayerClient>& listener) = 0;
virtual status_t prepare() = 0;
virtual status_t start() = 0;
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index 2a1298a..4b6f19d 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -45,6 +45,7 @@ public:
virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setParameters(const String8& params);
+ virtual status_t setCameraParameters(const String8& params);
virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
virtual status_t prepare();
virtual status_t start();
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 9ea6c7b..0f5aed1 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -167,6 +167,7 @@ public:
status_t setVideoSize(int width, int height);
status_t setVideoFrameRate(int frames_per_second);
status_t setParameters(const String8& params);
+ status_t setCameraParameters(const String8& params);
status_t setListener(const sp<MediaRecorderListener>& listener);
status_t prepare();
status_t getMaxAmplitude(int* max);
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 3b18c77..3896485 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -57,7 +57,8 @@ public:
CLASS_TOUCHSCREEN = 0x00000004,
CLASS_TRACKBALL = 0x00000008,
CLASS_TOUCHSCREEN_MT= 0x00000010,
- CLASS_DPAD = 0x00000020
+ CLASS_DPAD = 0x00000020,
+ CLASS_MOUSE = 0x00000040
};
uint32_t getDeviceClasses(int32_t deviceId) const;
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index 571e47b..f9f86234 100644
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -114,6 +114,15 @@ static const KeycodeLabel KEYCODES[] = {
{ "MEDIA_REWIND", 89 },
{ "MEDIA_FAST_FORWARD", 90 },
{ "MUTE", 91 },
+ { "FUNC_1", 92 },
+ { "FUNC_2", 93 },
+ { "FUNC_3", 94 },
+ { "FUNC_4", 95 },
+ { "FUNC_5", 96 },
+ { "FUNC_6", 97 },
+ { "FUNC_7", 98 },
+ { "FUNC_8", 99 },
+ { "QUECHAR", 100 },
// NOTE: If you add a new keycode here you must also add it to:
// (enum KeyCode, in this file)
@@ -218,7 +227,16 @@ typedef enum KeyCode {
kKeyCodePreviousSong = 88,
kKeyCodeRewind = 89,
kKeyCodeForward = 90,
- kKeyCodeMute = 91
+ kKeyCodeMute = 91,
+ kKeyCodeFunc1 = 92,
+ kKeyCodeFunc2 = 93,
+ kKeyCodeFunc3 = 94,
+ kKeyCodeFunc4 = 95,
+ kKeyCodeFunc5 = 96,
+ kKeyCodeFunc6 = 97,
+ kKeyCodeFunc7 = 98,
+ kKeyCodeFunc8 = 99,
+ kKeyCodeQuechar = 100
} KeyCode;
static const KeycodeLabel FLAGS[] = {
diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h
index a9ae1c4..9156e80 100644
--- a/include/ui/Overlay.h
+++ b/include/ui/Overlay.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,6 +92,7 @@ public:
/* set the buffer attributes */
status_t setParameter(int param, int value);
+ status_t setFd(int fd);
/* returns the address of a given buffer if supported, NULL otherwise. */
void* getBufferAddress(overlay_buffer_t buffer);
diff --git a/include/utils/Asset.h b/include/utils/Asset.h
index 5908bcc..b2697d4 100644
--- a/include/utils/Asset.h
+++ b/include/utils/Asset.h
@@ -63,11 +63,7 @@ public:
enum {
/* data larger than this does not get uncompressed into a buffer */
-#ifdef HAVE_ANDROID_OS
- UNCOMPRESS_DATA_MAX = 1 * 1024 * 1024
-#else
- UNCOMPRESS_DATA_MAX = 2 * 1024 * 1024
-#endif
+ UNCOMPRESS_DATA_MAX = 3 * 1024 * 1024
};
/*
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 870c0b8..3082813 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -75,6 +75,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioDSP.cpp.arm \
AudioFlinger.cpp \
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
diff --git a/libs/audioflinger/AudioDSP.cpp b/libs/audioflinger/AudioDSP.cpp
new file mode 100644
index 0000000..c56773b
--- /dev/null
+++ b/libs/audioflinger/AudioDSP.cpp
@@ -0,0 +1,651 @@
+/* //device/include/server/AudioFlinger/AudioDSP.cpp
+**
+** Copyright 2010, Antti S. Lankila
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <math.h>
+#include <stdio.h>
+
+#include "AudioDSP.h"
+
+namespace android {
+
+/* Keep this in sync with AudioMixer's FP decimal count. We
+ * use this count to generate the dither for ditherAndClamp(),
+ * among other things. */
+static const int32_t fixedPointDecimals = 12;
+static const int32_t fixedPointBits = (1 << fixedPointDecimals) - 1;
+
+static int16_t toFixedPoint(float x)
+{
+ return int16_t(x * (1 << fixedPointDecimals) + 0.5f);
+}
+
+
+/***************************************************************************
+ * Delay *
+ ***************************************************************************/
+Delay::Delay()
+ : mState(0), mIndex(0), mLength(0)
+{
+}
+
+Delay::~Delay()
+{
+ if (mState != 0) {
+ delete[] mState;
+ mState = 0;
+ }
+}
+
+void Delay::setParameters(float samplingFrequency, float time)
+{
+ mLength = int32_t(time * samplingFrequency + 0.5f);
+ if (mState != 0) {
+ delete[] mState;
+ }
+ mState = new int32_t[mLength];
+ memset(mState, 0, mLength * sizeof(int32_t));
+ mIndex = 0;
+}
+
+inline int32_t Delay::process(int32_t x0)
+{
+ int32_t y0 = mState[mIndex];
+ mState[mIndex] = x0;
+ mIndex = (mIndex + 1) % mLength;
+ return y0;
+}
+
+
+/***************************************************************************
+ * Allpass *
+ ***************************************************************************/
+Allpass::Allpass()
+ : mK(0), mState(0), mIndex(0), mLength(0)
+{
+}
+
+Allpass::~Allpass()
+{
+ if (mState != 0) {
+ delete[] mState;
+ mState = 0;
+ }
+}
+
+void Allpass::setParameters(float samplingFrequency, float k, float time)
+{
+ mK = toFixedPoint(k);
+ mLength = int32_t(time * samplingFrequency + 0.5f);
+ if (mState != 0) {
+ delete[] mState;
+ }
+ mState = new int32_t[mLength];
+ memset(mState, 0, mLength * sizeof(int32_t));
+ mIndex = 0;
+}
+
+inline int32_t Allpass::process(int32_t x0)
+{
+ int32_t tmp = x0 - mK * (mState[mIndex] >> fixedPointDecimals);
+ int32_t y0 = mState[mIndex] + mK * (tmp >> fixedPointDecimals);
+ mState[mIndex] = tmp;
+ mIndex = (mIndex + 1) % mLength;
+ return y0;
+}
+
+
+/***************************************************************************
+ * Biquad *
+ ***************************************************************************/
+Biquad::Biquad()
+ : mB0(0), mY0(0)
+{
+ state.i32.mA = 0;
+ state.i32.mB = 0;
+ state.i32.mX = 0;
+ state.i32.mY = 0;
+}
+
+void Biquad::setCoefficients(float a0, float a1, float a2, float b0, float b1, float b2)
+{
+ state.i16.mA1 = -toFixedPoint(a1/a0);
+ state.i16.mA2 = -toFixedPoint(a2/a0);
+ mB0 = toFixedPoint(b0/a0);
+ state.i16.mB1 = toFixedPoint(b1/a0);
+ state.i16.mB2 = toFixedPoint(b2/a0);
+}
+
+void Biquad::setRC(float center_frequency, float sampling_frequency)
+{
+ float DT_div_RC = 2 * (float) M_PI * center_frequency / sampling_frequency;
+ float b0 = DT_div_RC / (1 + DT_div_RC);
+ float a1 = -1 + b0;
+
+ setCoefficients(1, a1, 0, b0, 0, 0);
+}
+
+void Biquad::reset()
+{
+ mY0 = 0;
+ state.i32.mX = 0;
+ state.i32.mY = 0;
+}
+
+/*
+ * Peaking equalizer, low shelf and high shelf are taken from
+ * the good old Audio EQ Cookbook by Robert Bristow-Johnson.
+ */
+void Biquad::setPeakingEqualizer(float center_frequency, float sampling_frequency, float db_gain, float bandwidth)
+{
+ float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
+ float A = powf(10, db_gain/40);
+
+ float alpha = sinf(w0)/2 * sinhf( logf(2)/2 * bandwidth * w0/sinf(w0) );
+ float b0 = 1 + alpha*A;
+ float b1 = -2*cosf(w0);
+ float b2 = 1 - alpha*A;
+ float a0 = 1 + alpha/A;
+ float a1 = -2*cosf(w0);
+ float a2 = 1 - alpha/A;
+
+ setCoefficients(a0, a1, a2, b0, b1, b2);
+}
+
+void Biquad::setLowShelf(float center_frequency, float sampling_frequency, float db_gain, float slope)
+{
+ float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
+ float A = powf(10, db_gain/40);
+ float alpha = sinf(w0)/2 * sqrtf( (A + 1/A)*(1/slope - 1) + 2 );
+
+ float b0 = A*( (A+1) - (A-1)*cosf(w0) + 2*sqrtf(A)*alpha );
+ float b1 = 2*A*( (A-1) - (A+1)*cosf(w0) );
+ float b2 = A*( (A+1) - (A-1)*cosf(w0) - 2*sqrtf(A)*alpha );
+ float a0 = (A+1) + (A-1)*cosf(w0) + 2*sqrtf(A)*alpha ;
+ float a1 = -2*( (A-1) + (A+1)*cosf(w0) );
+ float a2 = (A+1) + (A-1)*cosf(w0) - 2*sqrtf(A)*alpha ;
+
+ setCoefficients(a0, a1, a2, b0, b1, b2);
+}
+
+void Biquad::setHighShelf(float center_frequency, float sampling_frequency, float db_gain, float slope)
+{
+ float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
+ float A = powf(10, db_gain/40);
+ float alpha = sinf(w0)/2 * sqrtf( (A + 1/A)*(1/slope - 1) + 2 );
+
+ float b0 = A*( (A+1) + (A-1)*cosf(w0) + 2*sqrtf(A)*alpha );
+ float b1 = -2*A*( (A-1) + (A+1)*cosf(w0) );
+ float b2 = A*( (A+1) + (A-1)*cosf(w0) - 2*sqrtf(A)*alpha );
+ float a0 = (A+1) - (A-1)*cosf(w0) + 2*sqrtf(A)*alpha ;
+ float a1 = 2*( (A-1) - (A+1)*cosf(w0) );
+ float a2 = (A+1) - (A-1)*cosf(w0) - 2*sqrtf(A)*alpha ;
+
+ setCoefficients(a0, a1, a2, b0, b1, b2);
+}
+
+void Biquad::setBandPass(float center_frequency, float sampling_frequency, float resonance)
+{
+ float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
+ float alpha = sinf(w0) / (2*resonance);
+
+ float b0 = sinf(w0)/2;
+ float b1 = 0;
+ float b2 = -sinf(w0)/2;
+ float a0 = 1 + alpha;
+ float a1 = -2*cosf(w0);
+ float a2 = 1 - alpha;
+
+ setCoefficients(a0, a1, a2, b0, b1, b2);
+}
+
+/* returns output scaled by fixedPoint factor */
+inline int32_t Biquad::process(int16_t x0)
+{
+ /* mY0 holds error from previous integer truncation. */
+ int32_t y0 = mY0 + mB0 * x0;
+
+#if defined(__arm__) && !defined(__thumb__)
+ asm(
+ "smlatt %[y0], %[i], %[j], %[y0]\n"
+ "smlabb %[y0], %[i], %[j], %[y0]\n"
+ "smlatt %[y0], %[k], %[l], %[y0]\n"
+ "smlabb %[y0], %[k], %[l], %[y0]\n"
+ : [y0]"+r"(y0)
+ : [i]"r"(state.i32.mA), [j]"r"(state.i32.mY),
+ [k]"r"(state.i32.mB), [l]"r"(state.i32.mX)
+ : );
+
+ /* GCC is going to issue loads for the state.i16, so I do it
+ * like this because the state.i32 is already in registers.
+ * ARM appears to have instructions that can handle these
+ * bit manipulations well, such as "orr r0, r0, r1, lsl #16".
+ */
+ state.i32.mY = (state.i32.mY << 16) | ((y0 >> fixedPointDecimals) & 0xffff);
+ state.i32.mX = (state.i32.mX << 16) | (x0 & 0xffff);
+#else
+ y0 += state.i16.mB1 * state.i16.mX1
+ + state.i16.mB2 * state.i16.mX2
+ + state.i16.mY1 * state.i16.mA1
+ + state.i16.mY2 * state.i16.mA2;
+
+ state.i16.mY2 = state.i16.mY1;
+ state.i16.mY1 = y0 >> fixedPointDecimals;
+
+ state.i16.mX2 = state.i16.mX1;
+ state.i16.mX1 = x0;
+#endif
+
+ mY0 = y0 & fixedPointBits;
+ return y0;
+}
+
+
+/***************************************************************************
+ * Effect *
+ ***************************************************************************/
+Effect::Effect()
+{
+ configure(44100);
+}
+
+Effect::~Effect() {
+}
+
+void Effect::configure(const float samplingFrequency) {
+ mSamplingFrequency = samplingFrequency;
+}
+
+
+EffectCompression::EffectCompression()
+ : mCompressionRatio(2.0)
+{
+}
+
+EffectCompression::~EffectCompression()
+{
+}
+
+void EffectCompression::configure(const float samplingFrequency)
+{
+ Effect::configure(samplingFrequency);
+ mWeighter.setBandPass(1000, samplingFrequency, sqrtf(2)/2);
+}
+
+void EffectCompression::setRatio(float compressionRatio)
+{
+ mCompressionRatio = compressionRatio;
+}
+
+void EffectCompression::process(int32_t* inout, int32_t frames)
+{
+}
+
+float EffectCompression::estimateLevel(const int16_t* audioData, int32_t frames, int32_t samplesPerFrame)
+{
+ mWeighter.reset();
+ uint32_t power = 0;
+ uint32_t powerFraction = 0;
+ for (int32_t i = 0; i < frames; i ++) {
+ int16_t tmp = *audioData;
+ audioData += samplesPerFrame;
+
+ int32_t out = mWeighter.process(tmp) >> 12;
+ powerFraction += out * out;
+ power += powerFraction >> 16;
+ powerFraction &= 0xffff;
+ }
+
+ /* peak-to-peak is -32768 to 32767, but we are squared here. */
+ return (65536.0f * power + powerFraction) / (32768.0f * 32768.0f) / frames;
+}
+
+
+EffectTone::EffectTone()
+{
+ for (int32_t i = 0; i < 5; i ++) {
+ mBand[i] = 0;
+ }
+ for (int32_t i = 0; i < 5; i ++) {
+ setBand(i, 0);
+ }
+}
+
+EffectTone::~EffectTone() {
+ for (int32_t i = 0; i < 4; i ++) {
+ delete &mFilterL[i];
+ delete &mFilterR[i];
+ }
+}
+
+void EffectTone::configure(const float samplingFrequency) {
+ Effect::configure(samplingFrequency);
+ refreshBands();
+}
+
+void EffectTone::setBand(int32_t band, float dB)
+{
+ mBand[band] = dB;
+ refreshBands();
+}
+
+void EffectTone::refreshBands() {
+ mGain = toFixedPoint(powf(10, mBand[0] / 20));
+
+ for (int32_t band = 0; band < 3; band ++) {
+ float dB = mBand[band + 1] - mBand[0];
+ float centerFrequency = 250.0f * powf(4, band);
+
+ mFilterL[band].setPeakingEqualizer(centerFrequency, mSamplingFrequency, dB, 3.0f);
+ mFilterR[band].setPeakingEqualizer(centerFrequency, mSamplingFrequency, dB, 3.0f);
+ }
+
+ {
+ int32_t band = 3;
+
+ float dB = mBand[band + 1] - mBand[0];
+ float centerFrequency = 250.0f * powf(4, band);
+
+ mFilterL[band].setHighShelf(centerFrequency * 0.5f, mSamplingFrequency, dB, 1.0f);
+ mFilterR[band].setHighShelf(centerFrequency * 0.5f, mSamplingFrequency, dB, 1.0f);
+ }
+}
+
+void EffectTone::process(int32_t* inout, int32_t frames)
+{
+ for (int32_t i = 0; i < frames; i ++) {
+ int32_t tmpL = inout[0] >> fixedPointDecimals;
+ int32_t tmpR = inout[1] >> fixedPointDecimals;
+ /* 16 bits */
+
+ /* bass control is really a global gain compensated by other
+ * controls */
+ tmpL = tmpL * mGain;
+ tmpR = tmpR * mGain;
+ /* 28 bits */
+
+ /* evaluate the other filters.
+ * I'm ignoring the integer truncation problem here, but in reality
+ * it should be accounted for. */
+ for (int32_t j = 0; j < 4; j ++) {
+ tmpL = mFilterL[j].process(tmpL >> fixedPointDecimals);
+ tmpR = mFilterR[j].process(tmpR >> fixedPointDecimals);
+ }
+ /* 28 bits */
+
+ inout[0] = tmpL;
+ inout[1] = tmpR;
+ inout += 2;
+ }
+}
+
+EffectHeadphone::EffectHeadphone()
+ : mDeep(true), mWide(true),
+ mDelayDataL(0), mDelayDataR(0)
+{
+ setLevel(0);
+}
+
+EffectHeadphone::~EffectHeadphone()
+{
+ delete &mReverbDelayL;
+ delete &mReverbDelayR;
+ delete &mDelayL;
+ delete &mDelayR;
+ for (int32_t i = 0; i < 3; i ++) {
+ delete &mAllpassL[i];
+ delete &mAllpassR[i];
+ }
+ delete &mLowpassL;
+ delete &mLowpassR;
+}
+
+void EffectHeadphone::configure(const float samplingFrequency) {
+ Effect::configure(samplingFrequency);
+
+ mReverbDelayL.setParameters(mSamplingFrequency, 0.030f);
+ mReverbDelayR.setParameters(mSamplingFrequency, 0.030f);
+ mDelayL.setParameters(mSamplingFrequency, 0.00045f);
+ mDelayR.setParameters(mSamplingFrequency, 0.00045f);
+ mAllpassL[0].setParameters(mSamplingFrequency, 0.4f, 0.00031f);
+ mAllpassR[0].setParameters(mSamplingFrequency, 0.4f, 0.00031f);
+ mAllpassL[1].setParameters(mSamplingFrequency, 0.4f, 0.00021f);
+ mAllpassR[1].setParameters(mSamplingFrequency, 0.4f, 0.00021f);
+ mAllpassL[2].setParameters(mSamplingFrequency, 0.4f, 0.00011f);
+ mAllpassR[2].setParameters(mSamplingFrequency, 0.4f, 0.00011f);
+ mLowpassL.setRC(4000.0f, mSamplingFrequency);
+ mLowpassR.setRC(4000.0f, mSamplingFrequency);
+}
+
+void EffectHeadphone::setDeep(bool deep)
+{
+ mDeep = deep;
+}
+
+void EffectHeadphone::setWide(bool wide)
+{
+ mWide = wide;
+}
+
+void EffectHeadphone::setLevel(float level)
+{
+ mLevel = toFixedPoint(powf(10, (level - 15.0f) / 20.0f));
+}
+
+void EffectHeadphone::process(int32_t* inout, int32_t frames)
+{
+ for (int32_t i = 0; i < frames; i ++) {
+ /* calculate reverb wet into dataL, dataR */
+ int32_t dryL = inout[0];
+ int32_t dryR = inout[1];
+ int32_t dataL = dryL;
+ int32_t dataR = dryR;
+ /* 28 bits */
+
+ if (mDeep) {
+ dataL += mDelayDataR;
+ dataR += mDelayDataL;
+ }
+
+ dataL = mReverbDelayL.process(dataL);
+ dataR = mReverbDelayR.process(dataR);
+ /* 28 bits */
+
+ if (mWide) {
+ dataR = -dataR;
+ }
+
+ dataL = (dataL >> fixedPointDecimals) * mLevel;
+ dataR = (dataR >> fixedPointDecimals) * mLevel;
+ /* 28 bits */
+
+ mDelayDataL = dataL;
+ mDelayDataR = dataR;
+
+ /* Reverb wet done; mix with dry and do headphone virtualization */
+ dataL += dryL;
+ dataR += dryR;
+
+ /* Add fixed ear-to-ear propagation delay of about 10 cm, based
+ * on the idea that ear-to-ear distance is 30 cm and the speakers
+ * are placed in front of the listener, which means that the actual
+ * time delay will be somewhat less than the maximum. */
+ dataL = mDelayL.process(dataL);
+ dataR = mDelayR.process(dataR);
+ for (int32_t j = 0; j < 3; j ++) {
+ /* Confuse phase, simulating shoulder echoes and whatnot. */
+ dataL = mAllpassL[j].process(dataL);
+ dataR = mAllpassR[j].process(dataR);
+ }
+
+ /* Lowpass filter to estimate head shadow. */
+ dataL = mLowpassL.process(dataL >> fixedPointDecimals);
+ dataR = mLowpassR.process(dataR >> fixedPointDecimals);
+ /* 28 bits */
+
+ /* Mix right-to-left and vice versa. */
+ inout[0] += dataR;
+ inout[1] += dataL;
+ inout += 2;
+ }
+}
+
+
+/***************************************************************************
+ * AudioDSP *
+ ***************************************************************************/
+const String8 AudioDSP::keyCompressionEnable = String8("dsp.compression.enable");
+const String8 AudioDSP::keyCompressionRatio = String8("dsp.compression.ratio");
+
+const String8 AudioDSP::keyToneEnable = String8("dsp.tone.enable");
+const String8 AudioDSP::keyToneEq1 = String8("dsp.tone.eq1");
+const String8 AudioDSP::keyToneEq2 = String8("dsp.tone.eq2");
+const String8 AudioDSP::keyToneEq3 = String8("dsp.tone.eq3");
+const String8 AudioDSP::keyToneEq4 = String8("dsp.tone.eq4");
+const String8 AudioDSP::keyToneEq5 = String8("dsp.tone.eq5");
+
+const String8 AudioDSP::keyHeadphoneEnable = String8("dsp.headphone.enable");
+const String8 AudioDSP::keyHeadphoneDeep = String8("dsp.headphone.deep");
+const String8 AudioDSP::keyHeadphoneWide = String8("dsp.headphone.wide");
+const String8 AudioDSP::keyHeadphoneLevel = String8("dsp.headphone.level");
+
+AudioDSP::AudioDSP()
+ : mCompressionEnable(false), mToneEnable(false), mHeadphoneEnable(false)
+{
+}
+
+AudioDSP::~AudioDSP()
+{
+ delete &mCompression;
+ delete &mTone;
+ delete &mHeadphone;
+}
+
+void AudioDSP::configure(const float samplingRate)
+{
+ mCompression.configure(samplingRate);
+ mTone.configure(samplingRate);
+ mHeadphone.configure(samplingRate);
+}
+
+void AudioDSP::setParameters(const String8& keyValuePairs)
+{
+ int intValue;
+ float floatValue;
+ status_t result;
+ AudioParameter param = AudioParameter(keyValuePairs);
+
+ result = param.getInt(keyCompressionEnable, intValue);
+ if (result == NO_ERROR) {
+ mCompressionEnable = intValue != 0;
+ }
+ result = param.getFloat(keyCompressionRatio, floatValue);
+ if (result == NO_ERROR) {
+ mCompression.setRatio(floatValue);
+ }
+
+ result = param.getInt(keyToneEnable, intValue);
+ if (result == NO_ERROR) {
+ mToneEnable = intValue != 0;
+ }
+ result = param.getFloat(keyToneEq1, floatValue);
+ if (result == NO_ERROR) {
+ mTone.setBand(0, floatValue);
+ }
+ result = param.getFloat(keyToneEq2, floatValue);
+ if (result == NO_ERROR) {
+ mTone.setBand(1, floatValue);
+ }
+ result = param.getFloat(keyToneEq3, floatValue);
+ if (result == NO_ERROR) {
+ mTone.setBand(2, floatValue);
+ }
+ result = param.getFloat(keyToneEq4, floatValue);
+ if (result == NO_ERROR) {
+ mTone.setBand(3, floatValue);
+ }
+ result = param.getFloat(keyToneEq5, floatValue);
+ if (result == NO_ERROR) {
+ mTone.setBand(4, floatValue);
+ }
+
+ result = param.getInt(keyHeadphoneEnable, intValue);
+ if (result == NO_ERROR) {
+ mHeadphoneEnable = intValue != 0;
+ }
+ result = param.getInt(keyHeadphoneDeep, intValue);
+ if (result == NO_ERROR) {
+ mHeadphone.setDeep(intValue != 0);
+ }
+ result = param.getInt(keyHeadphoneWide, intValue);
+ if (result == NO_ERROR) {
+ mHeadphone.setWide(intValue != 0);
+ }
+ result = param.getFloat(keyHeadphoneLevel, floatValue);
+ if (result == NO_ERROR) {
+ mHeadphone.setLevel(floatValue);
+ }
+}
+
+int32_t AudioDSP::estimateLevel(const int16_t* input, int32_t frames, int32_t samplesPerFrame)
+{
+ if (! mCompressionEnable) {
+ return 65536;
+ }
+
+ /* Analyze both channels separately, pick the maximum power measured. */
+ float maximumPowerSquared = 0;
+ for (int channel = 0; channel < samplesPerFrame; channel ++) {
+ float candidatePowerSquared = mCompression.estimateLevel(input + channel, frames, samplesPerFrame);
+ if (candidatePowerSquared > maximumPowerSquared) {
+ maximumPowerSquared = candidatePowerSquared;
+ }
+ }
+
+ /* -100 .. 0 dB. */
+ float signalPowerDb = logf(maximumPowerSquared + 1e-10f) / logf(10.0f) * 10.0f;
+
+ /* target 83 dB SPL, and add 6 dB to compensate for the weighter, whose
+ * peak is at -3 dB. */
+ signalPowerDb += 96.0f - 83.0f + 6.0f;
+
+ /* now we have an estimate of the signal power, with 0 level around 83 dB.
+ * we now select the level to boost to. */
+ float desiredLevelDb = signalPowerDb / mCompression.mCompressionRatio;
+
+ /* turn back to multiplier */
+ float correctionDb = desiredLevelDb - signalPowerDb;
+
+ /* Reduce extreme boost by a smooth ramp.
+ * New range -50 .. 0 dB */
+ correctionDb -= powf(correctionDb/100, 2.0f) * (100.0f / 2.0f);
+
+ return int32_t(65536.0f * powf(10.0f, correctionDb / 20.0f));
+}
+
+/* input is 28-bit interleaved stereo in integer format */
+void AudioDSP::process(int32_t* audioData, int32_t frames)
+{
+ if (mToneEnable) {
+ mTone.process(audioData, frames);
+ }
+
+ if (mHeadphoneEnable) {
+ mHeadphone.process(audioData, frames);
+ }
+}
+
+}
diff --git a/libs/audioflinger/AudioDSP.h b/libs/audioflinger/AudioDSP.h
new file mode 100644
index 0000000..99cc299
--- /dev/null
+++ b/libs/audioflinger/AudioDSP.h
@@ -0,0 +1,173 @@
+/* //device/include/server/AudioFlinger/AudioDSP.h
+**
+** Copyright 2010, Antti S Lankila
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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_AUDIODSP_H
+#define ANDROID_AUDIODSP_H 1
+
+#include <media/AudioSystem.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class Delay {
+ int32_t* mState;
+ int32_t mIndex;
+ int32_t mLength;
+
+ public:
+ Delay();
+ ~Delay();
+ void setParameters(float rate, float time);
+ int32_t process(int32_t x0);
+};
+
+class Allpass {
+ int32_t mK;
+ int32_t* mState;
+ int32_t mIndex;
+ int32_t mLength;
+
+ public:
+ Allpass();
+ ~Allpass();
+ void setParameters(float rate, float k, float time);
+ int32_t process(int32_t x0);
+};
+
+class Biquad {
+ union {
+ struct {
+ int32_t mA, mB, mY, mX;
+ } i32;
+ struct {
+ int16_t mA1, mA2, mB1, mB2, mY1, mY2, mX1, mX2;
+ } i16;
+ } state;
+ int16_t mB0, mY0;
+
+ void setCoefficients(float a0, float a1, float a2, float b0, float b1, float b2);
+
+ public:
+ Biquad();
+ void setRC(float cf, float sf);
+ void setPeakingEqualizer(float cf, float sf, float gain, float bw);
+ void setBandPass(float cf, float sf, float resonance);
+ void setLowShelf(float cf, float sf, float gain, float slope);
+ void setHighShelf(float cf, float sf, float gain, float slope);
+ void reset();
+ int32_t process(int16_t x0);
+};
+
+class Effect {
+ protected:
+ float mSamplingFrequency;
+
+ public:
+ Effect();
+ virtual ~Effect();
+ virtual void configure(const float samplingFrequency);
+ virtual void process(int32_t* inout, int32_t frames) = 0;
+};
+
+class EffectCompression : public Effect {
+ private:
+ Biquad mWeighter;
+
+ public:
+ float mCompressionRatio;
+
+ EffectCompression();
+ ~EffectCompression();
+ void configure(const float samplingFrequency);
+ void setRatio(float compressionRatio);
+ void process(int32_t* inout, int32_t frames);
+ float estimateLevel(const int16_t* audiodata, int32_t frames, int32_t framesPerSample);
+};
+
+class EffectTone : public Effect {
+ float mBand[5];
+ int32_t mGain;
+ Biquad mFilterL[4], mFilterR[4];
+
+ void refreshBands();
+
+ public:
+ EffectTone();
+ ~EffectTone();
+ void configure(const float samplingFrequency);
+ void setBand(int32_t idx, float dB);
+ void process(int32_t* inout, int32_t frames);
+};
+
+class EffectHeadphone : public Effect {
+ bool mDeep, mWide;
+ int32_t mLevel;
+
+ Delay mReverbDelayL, mReverbDelayR;
+ int32_t mDelayDataL, mDelayDataR;
+ Delay mDelayL, mDelayR;
+ Allpass mAllpassL[3], mAllpassR[3];
+ Biquad mLowpassL, mLowpassR;
+
+ public:
+ EffectHeadphone();
+ ~EffectHeadphone();
+ void configure(const float samplingFrequency);
+ void setDeep(bool enable);
+ void setWide(bool enable);
+ void setLevel(float level);
+ void process(int32_t* inout, int32_t frames);
+};
+
+class AudioDSP {
+ bool mCompressionEnable;
+ EffectCompression mCompression;
+
+ bool mToneEnable;
+ EffectTone mTone;
+
+ bool mHeadphoneEnable;
+ EffectHeadphone mHeadphone;
+
+ public:
+ AudioDSP();
+ ~AudioDSP();
+
+ void configure(float samplingRate);
+ void setParameters(const String8& keyValuePairs);
+ int32_t estimateLevel(const int16_t* audiodata, int32_t frames, int32_t samplesPerFrame);
+ void process(int32_t* inputInterleaved, int32_t frames);
+
+ static const String8 keyCompressionEnable;
+ static const String8 keyCompressionRatio;
+
+ static const String8 keyToneEnable;
+ static const String8 keyToneEq1;
+ static const String8 keyToneEq2;
+ static const String8 keyToneEq3;
+ static const String8 keyToneEq4;
+ static const String8 keyToneEq5;
+
+ static const String8 keyHeadphoneEnable;
+ static const String8 keyHeadphoneDeep;
+ static const String8 keyHeadphoneWide;
+ static const String8 keyHeadphoneLevel;
+};
+
+}
+
+#endif
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 2414e8d..890692d 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -605,6 +605,8 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
// ioHandle == 0 means the parameters are global to the audio hardware interface
if (ioHandle == 0) {
+ /* Set global DSP parameters, if any. */
+ mDsp.setParameters(keyValuePairs);
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_SET_PARAMETER;
result = mAudioHardware->setParameters(keyValuePairs);
@@ -1287,7 +1289,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
mAudioMixer(0)
{
mType = PlaybackThread::MIXER;
- mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate, audioFlinger->mDsp);
// FIXME - Current mixer implementation only supports stereo output
if (mChannelCount == 1) {
@@ -1727,7 +1729,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
if (status == NO_ERROR && reconfig) {
delete mAudioMixer;
readOutputParameters();
- mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate, mAudioFlinger->mDsp);
for (size_t i = 0; i < mTracks.size() ; i++) {
int name = getTrackName_l();
if (name < 0) break;
@@ -3067,7 +3069,11 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
: RefBase(),
mAudioFlinger(audioFlinger),
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mMemoryDealer(new MemoryDealer(1024*1024)),
+#else
mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
+#endif
mPid(pid)
{
// 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 739ec33..05915e5 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -31,13 +31,18 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
#include <binder/MemoryDealer.h>
+#else
+#include <binder/MemoryDealer.h>
+#endif
#include <utils/SortedVector.h>
#include <utils/Vector.h>
#include <hardware_legacy/AudioHardwareInterface.h>
#include "AudioBufferProvider.h"
+#include "AudioDSP.h"
namespace android {
@@ -798,6 +803,8 @@ private:
SortedVector< sp<IBinder> > mNotificationClients;
int mNextThreadId;
+
+ AudioDSP mDsp;
};
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 19a442a..e5985d7 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -38,11 +38,18 @@ static inline int16_t clamp16(int32_t sample)
return sample;
}
+static int32_t seed = 1;
+inline static int32_t prng() {
+ seed = (seed * 12345) + 1103515245;
+ return int32_t(seed & 0xfff);
+}
+
// ----------------------------------------------------------------------------
-AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
- : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
+AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, AudioDSP& dsp)
+ : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate), mDsp(dsp)
{
+ mDsp.configure(sampleRate);
mState.enabledTracks= 0;
mState.needsChanged = 0;
mState.frameCount = frameCount;
@@ -202,18 +209,10 @@ status_t AudioMixer::setParameter(int target, int name, int value)
if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
track_t& track = mState.tracks[ mActiveTrack ];
if (track.volume[name-VOLUME0] != value) {
- track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
track.volume[name-VOLUME0] = value;
if (target == VOLUME) {
track.prevVolume[name-VOLUME0] = value << 16;
track.volumeInc[name-VOLUME0] = 0;
- } else {
- int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
- int32_t volInc = d / int32_t(mState.frameCount);
- track.volumeInc[name-VOLUME0] = volInc;
- if (volInc == 0) {
- track.prevVolume[name-VOLUME0] = value << 16;
- }
}
invalidateState(1<<mActiveTrack);
}
@@ -244,15 +243,34 @@ bool AudioMixer::track_t::doesResample() const
return resampler != 0;
}
-inline
-void AudioMixer::track_t::adjustVolumeRamp()
+void AudioMixer::track_t::adjustVolumeRamp(AudioDSP& dsp, size_t frames)
{
- for (int i=0 ; i<2 ; i++) {
- if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
- ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
- volumeInc[i] = 0;
- prevVolume[i] = volume[i]<<16;
+ int32_t dynamicRangeCompressionFactor = dsp.estimateLevel(
+ static_cast<const int16_t*>(in), int32_t(frames), channelCount
+ );
+
+ for (int i = 0; i < 2; i ++) {
+ /* Ramp from current to new volume level if necessary */
+ int32_t desiredVolume = volume[i] * dynamicRangeCompressionFactor;
+ int32_t d = desiredVolume - prevVolume[i];
+
+ /* limit change rate to smooth the compressor. */
+ int32_t volChangeLimit = (prevVolume[i] >> 10);
+
+ volChangeLimit += 1;
+ int32_t volInc = d / int32_t(frames);
+ if (volInc < -(volChangeLimit)) {
+ volInc = -(volChangeLimit);
}
+
+ /* Make ramps up slower, but ramps down fast. */
+ volChangeLimit >>= 3;
+ volChangeLimit -= 1;
+ if (volInc > volChangeLimit) {
+ volInc = volChangeLimit;
+ }
+
+ volumeInc[i] = volInc;
}
}
@@ -267,11 +285,11 @@ status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
void AudioMixer::process(void* output)
{
- mState.hook(&mState, output);
+ mState.hook(&mState, output, mDsp);
}
-void AudioMixer::process__validate(state_t* state, void* output)
+void AudioMixer::process__validate(state_t* state, void* output, AudioDSP& dsp)
{
LOGW_IF(!state->needsChanged,
"in process__validate() but nothing's invalid");
@@ -356,11 +374,6 @@ void AudioMixer::process__validate(state_t* state, void* output)
state->resampleTemp = 0;
}
state->hook = process__genericNoResampling;
- if (all16BitsStereoNoResample && !volumeRamp) {
- if (countActiveTracks == 1) {
- state->hook = process__OneTrack16BitsStereoNoResampling;
- }
- }
}
}
@@ -369,7 +382,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
countActiveTracks, state->enabledTracks,
all16BitsStereoNoResample, resampling, volumeRamp);
- state->hook(state, output);
+ state->hook(state, output, dsp);
// Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
@@ -390,10 +403,6 @@ void AudioMixer::process__validate(state_t* state, void* output)
}
if (allMuted) {
state->hook = process__nop;
- } else if (!resampling && all16BitsStereoNoResample) {
- if (countActiveTracks == 1) {
- state->hook = process__OneTrack16BitsStereoNoResampling;
- }
}
}
}
@@ -481,7 +490,7 @@ int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
}
-void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, AudioDSP& dsp)
{
t->resampler->setSampleRate(t->sampleRate);
@@ -490,7 +499,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram
t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
t->resampler->resample(temp, outFrameCount, t->bufferProvider);
- volumeRampStereo(t, out, outFrameCount, temp);
+ volumeRampStereo(t, out, outFrameCount, temp, dsp);
}
// constant gain
@@ -500,12 +509,13 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram
}
}
-void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, AudioDSP& dsp)
{
}
-void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp)
{
+ t->adjustVolumeRamp(dsp, frameCount);
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
const int32_t vlInc = t->volumeInc[0];
@@ -525,14 +535,14 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
- t->adjustVolumeRamp();
}
-void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp)
{
int16_t const *in = static_cast<int16_t const *>(t->in);
// ramp gain
+ t->adjustVolumeRamp(dsp, frameCount);
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
@@ -552,7 +562,6 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
- t->adjustVolumeRamp();
}
// constant gain
@@ -569,11 +578,12 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount
t->in = in;
}
-void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp)
{
int16_t const *in = static_cast<int16_t const *>(t->in);
// ramp gain
+ t->adjustVolumeRamp(dsp, frameCount);
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
@@ -594,7 +604,6 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
- t->adjustVolumeRamp();
}
// constant gain
else {
@@ -612,11 +621,20 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
{
+ int32_t oldDitherValue = prng();
for (size_t i=0 ; i<c ; i++) {
int32_t l = *sums++;
int32_t r = *sums++;
- int32_t nl = l >> 12;
- int32_t nr = r >> 12;
+
+ /* Apply dither to output. This is the high-passed triangular
+ * probability density function, discussed in "A Theory of
+ * Nonsubtractive Dither", by Robert A. Wannamaker et al. */
+ int32_t ditherValue = prng();
+ int32_t dithering = oldDitherValue - ditherValue;
+ oldDitherValue = ditherValue;
+
+ int32_t nl = (l + ditherValue) >> 12;
+ int32_t nr = (r + ditherValue) >> 12;
l = clamp16(nl);
r = clamp16(nr);
*out++ = (r<<16) | (l & 0xFFFF);
@@ -624,7 +642,7 @@ void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
}
// no-op case
-void AudioMixer::process__nop(state_t* state, void* output)
+void AudioMixer::process__nop(state_t* state, void* output, AudioDSP& dsp)
{
// this assumes output 16 bits stereo, no resampling
memset(output, 0, state->frameCount*4);
@@ -645,7 +663,7 @@ void AudioMixer::process__nop(state_t* state, void* output)
}
// generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+void AudioMixer::process__genericNoResampling(state_t* state, void* output, AudioDSP& dsp)
{
int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
@@ -682,7 +700,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
while (outFrames) {
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
if (inFrames) {
- (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
+ (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, dsp);
t.frameCount -= inFrames;
outFrames -= inFrames;
}
@@ -700,6 +718,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
}
}
+ dsp.process(outTemp, BLOCKSIZE);
ditherAndClamp(out, outTemp, BLOCKSIZE);
out += BLOCKSIZE;
numFrames -= BLOCKSIZE;
@@ -717,7 +736,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
}
// generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state, void* output)
+void AudioMixer::process__genericResampling(state_t* state, void* output, AudioDSP& dsp)
{
int32_t* const outTemp = state->outputTemp;
const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
@@ -736,7 +755,7 @@ void AudioMixer::process__genericResampling(state_t* state, void* output)
// acquire/release the buffers because it's done by
// the resampler.
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
- (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+ (t.hook)(&t, outTemp, numFrames, state->resampleTemp, dsp);
} else {
size_t outFrames = numFrames;
@@ -749,167 +768,17 @@ void AudioMixer::process__genericResampling(state_t* state, void* output)
// been enabled for mixing.
if (t.in == NULL) break;
- (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
+ (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, dsp);
outFrames -= t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
}
}
}
+ dsp.process(outTemp, numFrames);
ditherAndClamp(out, outTemp, numFrames);
}
-// one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
-{
- const int i = 31 - __builtin_clz(state->enabledTracks);
- const track_t& t = state->tracks[i];
-
- AudioBufferProvider::Buffer& b(t.buffer);
-
- int32_t* out = static_cast<int32_t*>(output);
- size_t numFrames = state->frameCount;
-
- const int16_t vl = t.volume[0];
- const int16_t vr = t.volume[1];
- const uint32_t vrl = t.volumeRL;
- while (numFrames) {
- b.frameCount = numFrames;
- t.bufferProvider->getNextBuffer(&b);
- int16_t const *in = b.i16;
-
- // in == NULL can happen if the track was flushed just after having
- // been enabled for mixing.
- if (in == NULL || ((unsigned long)in & 3)) {
- memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
- LOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: buffer %p track %d, channels %d, needs %08x",
- in, i, t.channelCount, t.needs);
- return;
- }
- size_t outFrames = b.frameCount;
-
- if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
- // volume is boosted, so we might need to clamp even though
- // we process only one track.
- do {
- uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- // clamping...
- l = clamp16(l);
- r = clamp16(r);
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
- } else {
- do {
- uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
- }
- numFrames -= b.frameCount;
- t.bufferProvider->releaseBuffer(&b);
- }
-}
-
-// 2 tracks is also a common case
-void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
-{
- int i;
- uint32_t en = state->enabledTracks;
-
- i = 31 - __builtin_clz(en);
- const track_t& t0 = state->tracks[i];
- AudioBufferProvider::Buffer& b0(t0.buffer);
-
- en &= ~(1<<i);
- i = 31 - __builtin_clz(en);
- const track_t& t1 = state->tracks[i];
- AudioBufferProvider::Buffer& b1(t1.buffer);
-
- int16_t const *in0;
- const int16_t vl0 = t0.volume[0];
- const int16_t vr0 = t0.volume[1];
- size_t frameCount0 = 0;
-
- int16_t const *in1;
- const int16_t vl1 = t1.volume[0];
- const int16_t vr1 = t1.volume[1];
- size_t frameCount1 = 0;
-
- int32_t* out = static_cast<int32_t*>(output);
- size_t numFrames = state->frameCount;
- int16_t const *buff = NULL;
-
-
- while (numFrames) {
-
- if (frameCount0 == 0) {
- b0.frameCount = numFrames;
- t0.bufferProvider->getNextBuffer(&b0);
- if (b0.i16 == NULL) {
- if (buff == NULL) {
- buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
- }
- in0 = buff;
- b0.frameCount = numFrames;
- } else {
- in0 = b0.i16;
- }
- frameCount0 = b0.frameCount;
- }
- if (frameCount1 == 0) {
- b1.frameCount = numFrames;
- t1.bufferProvider->getNextBuffer(&b1);
- if (b1.i16 == NULL) {
- if (buff == NULL) {
- buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
- }
- in1 = buff;
- b1.frameCount = numFrames;
- } else {
- in1 = b1.i16;
- }
- frameCount1 = b1.frameCount;
- }
-
- size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
-
- numFrames -= outFrames;
- frameCount0 -= outFrames;
- frameCount1 -= outFrames;
-
- do {
- int32_t l0 = *in0++;
- int32_t r0 = *in0++;
- l0 = mul(l0, vl0);
- r0 = mul(r0, vr0);
- int32_t l = *in1++;
- int32_t r = *in1++;
- l = mulAdd(l, vl1, l0) >> 12;
- r = mulAdd(r, vr1, r0) >> 12;
- // clamping...
- l = clamp16(l);
- r = clamp16(r);
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
-
- if (frameCount0 == 0) {
- t0.bufferProvider->releaseBuffer(&b0);
- }
- if (frameCount1 == 0) {
- t1.bufferProvider->releaseBuffer(&b1);
- }
- }
-
- if (buff != NULL) {
- delete [] buff;
- }
-}
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 15766cd..9aa92ed 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include "AudioBufferProvider.h"
+#include "AudioDSP.h"
#include "AudioResampler.h"
namespace android {
@@ -36,7 +37,7 @@ namespace android {
class AudioMixer
{
public:
- AudioMixer(size_t frameCount, uint32_t sampleRate);
+ AudioMixer(size_t frameCount, uint32_t sampleRate, AudioDSP& dsp);
~AudioMixer();
@@ -88,7 +89,6 @@ public:
static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
private:
-
enum {
NEEDS_CHANNEL_COUNT__MASK = 0x00000003,
NEEDS_FORMAT__MASK = 0x000000F0,
@@ -116,7 +116,7 @@ private:
struct state_t;
- typedef void (*mix_t)(state_t* state, void* output);
+ typedef void (*mix_t)(state_t* state, void* output, AudioDSP& dsp);
static const int BLOCKSIZE = 16; // 4 cache lines
@@ -142,7 +142,7 @@ private:
AudioBufferProvider* bufferProvider;
mutable AudioBufferProvider::Buffer buffer;
- void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
+ void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, AudioDSP& dsp);
void const* in; // current location in buffer
AudioResampler* resampler;
@@ -150,7 +150,7 @@ private:
bool setResampler(uint32_t sampleRate, uint32_t devSampleRate);
bool doesResample() const;
- void adjustVolumeRamp();
+ void adjustVolumeRamp(AudioDSP& dsp, size_t frames);
};
// pad to 32-bytes to fill cache line
@@ -168,23 +168,22 @@ private:
int mActiveTrack;
uint32_t mTrackNames;
const uint32_t mSampleRate;
+ AudioDSP& mDsp;
state_t mState __attribute__((aligned(32)));
void invalidateState(uint32_t mask);
- static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
- static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
- static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
- static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
- static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
-
- static void process__validate(state_t* state, void* output);
- static void process__nop(state_t* state, void* output);
- static void process__genericNoResampling(state_t* state, void* output);
- static void process__genericResampling(state_t* state, void* output);
- static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
- static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
+ static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, AudioDSP& dsp);
+ static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, AudioDSP& dsp);
+ static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp);
+ static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, AudioDSP& dsp);
+ static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, AudioDSP& dsp);
+
+ static void process__validate(state_t* state, void* output, AudioDSP& dsp);
+ static void process__nop(state_t* state, void* output, AudioDSP& dsp);
+ static void process__genericNoResampling(state_t* state, void* output, AudioDSP& dsp);
+ static void process__genericResampling(state_t* state, void* output, AudioDSP& dsp);
};
// ----------------------------------------------------------------------------
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 13dc500..85cd488 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -21,7 +21,6 @@ sources := \
IPCThreadState.cpp \
IPermissionController.cpp \
IServiceManager.cpp \
- MemoryDealer.cpp \
MemoryBase.cpp \
MemoryHeapBase.cpp \
MemoryHeapPmem.cpp \
@@ -30,6 +29,13 @@ sources := \
ProcessState.cpp \
Static.cpp
+ifeq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_CFLAGS += -DUSE_ECLAIR_MEMORYDEALER
+ sources += MemoryDealerEclair.cpp
+else
+ sources += MemoryDealer.cpp
+endif
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
diff --git a/libs/binder/MemoryDealerEclair.cpp b/libs/binder/MemoryDealerEclair.cpp
new file mode 100644
index 0000000..a48a619
--- /dev/null
+++ b/libs/binder/MemoryDealerEclair.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MemoryDealer"
+#define USE_ECLAIR_MEMORYDEALER
+
+#include <binder/MemoryDealer.h>
+
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <binder/MemoryBase.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+HeapInterface::HeapInterface() { }
+HeapInterface::~HeapInterface() { }
+
+// ----------------------------------------------------------------------------
+
+AllocatorInterface::AllocatorInterface() { }
+AllocatorInterface::~AllocatorInterface() { }
+
+// ----------------------------------------------------------------------------
+
+class SimpleMemory : public MemoryBase {
+public:
+ SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+ virtual ~SimpleMemory();
+};
+
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::Allocation::Allocation(
+ const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
+ const sp<IMemory>& memory)
+ : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
+{
+}
+
+MemoryDealer::Allocation::~Allocation()
+{
+ if (mSize) {
+ /* NOTE: it's VERY important to not free allocations of size 0 because
+ * they're special as they don't have any record in the allocator
+ * and could alias some real allocation (their offset is zero). */
+ mDealer->deallocate(mOffset);
+ }
+}
+
+sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
+ ssize_t* offset, size_t* size) const
+{
+ return mMemory->getMemory(offset, size);
+}
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
+ : mHeap(new SharedHeap(size, flags, name)),
+ mAllocator(new SimpleBestFitAllocator(size))
+{
+}
+
+MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
+ : mHeap(heap),
+ mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
+{
+}
+
+MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator)
+ : mHeap(heap), mAllocator(allocator)
+{
+}
+
+MemoryDealer::~MemoryDealer()
+{
+}
+
+sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
+{
+ sp<IMemory> memory;
+ const ssize_t offset = allocator()->allocate(size, flags);
+ if (offset >= 0) {
+ sp<IMemory> new_memory = heap()->mapMemory(offset, size);
+ if (new_memory != 0) {
+ memory = new Allocation(this, offset, size, new_memory);
+ } else {
+ LOGE("couldn't map [%8lx, %u]", offset, size);
+ if (size) {
+ /* NOTE: it's VERY important to not free allocations of size 0
+ * because they're special as they don't have any record in the
+ * allocator and could alias some real allocation
+ * (their offset is zero). */
+ allocator()->deallocate(offset);
+ }
+ }
+ }
+ return memory;
+}
+
+void MemoryDealer::deallocate(size_t offset)
+{
+ allocator()->deallocate(offset);
+}
+
+void MemoryDealer::dump(const char* what, uint32_t flags) const
+{
+ allocator()->dump(what, flags);
+}
+
+const sp<HeapInterface>& MemoryDealer::heap() const {
+ return mHeap;
+}
+
+const sp<AllocatorInterface>& MemoryDealer::allocator() const {
+ return mAllocator;
+}
+
+// ----------------------------------------------------------------------------
+
+// align all the memory blocks on a cache-line boundary
+const int SimpleBestFitAllocator::kMemoryAlign = 32;
+
+SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
+{
+ size_t pagesize = getpagesize();
+ mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
+
+ chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
+ mList.insertHead(node);
+}
+
+SimpleBestFitAllocator::~SimpleBestFitAllocator()
+{
+ while(!mList.isEmpty()) {
+ delete mList.remove(mList.head());
+ }
+}
+
+size_t SimpleBestFitAllocator::size() const
+{
+ return mHeapSize;
+}
+
+size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ ssize_t offset = alloc(size, flags);
+ return offset;
+}
+
+status_t SimpleBestFitAllocator::deallocate(size_t offset)
+{
+ Mutex::Autolock _l(mLock);
+ chunk_t const * const freed = dealloc(offset);
+ if (freed) {
+ return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
+{
+ if (size == 0) {
+ return 0;
+ }
+ size = (size + kMemoryAlign-1) / kMemoryAlign;
+ chunk_t* free_chunk = 0;
+ chunk_t* cur = mList.head();
+
+ size_t pagesize = getpagesize();
+ while (cur) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
+
+ // best fit
+ if (cur->free && (cur->size >= (size+extra))) {
+ if ((!free_chunk) || (cur->size < free_chunk->size)) {
+ free_chunk = cur;
+ }
+ if (cur->size == size) {
+ break;
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (free_chunk) {
+ const size_t free_size = free_chunk->size;
+ free_chunk->free = 0;
+ free_chunk->size = size;
+ if (free_size > size) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
+ if (extra) {
+ chunk_t* split = new chunk_t(free_chunk->start, extra);
+ free_chunk->start += extra;
+ mList.insertBefore(free_chunk, split);
+ }
+
+ LOGE_IF((flags&PAGE_ALIGNED) &&
+ ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
+ "PAGE_ALIGNED requested, but page is not aligned!!!");
+
+ const ssize_t tail_free = free_size - (size+extra);
+ if (tail_free > 0) {
+ chunk_t* split = new chunk_t(
+ free_chunk->start + free_chunk->size, tail_free);
+ mList.insertAfter(free_chunk, split);
+ }
+ }
+ return (free_chunk->start)*kMemoryAlign;
+ }
+ return NO_MEMORY;
+}
+
+SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
+{
+ start = start / kMemoryAlign;
+ chunk_t* cur = mList.head();
+ while (cur) {
+ if (cur->start == start) {
+ LOG_FATAL_IF(cur->free,
+ "block at offset 0x%08lX of size 0x%08lX already freed",
+ cur->start*kMemoryAlign, cur->size*kMemoryAlign);
+
+ // merge freed blocks together
+ chunk_t* freed = cur;
+ cur->free = 1;
+ do {
+ chunk_t* const p = cur->prev;
+ chunk_t* const n = cur->next;
+ if (p && (p->free || !cur->size)) {
+ freed = p;
+ p->size += cur->size;
+ mList.remove(cur);
+ delete cur;
+ }
+ cur = n;
+ } while (cur && cur->free);
+
+ #ifndef NDEBUG
+ if (!freed->free) {
+ dump_l("dealloc (!freed->free)");
+ }
+ #endif
+ LOG_FATAL_IF(!freed->free,
+ "freed block at offset 0x%08lX of size 0x%08lX is not free!",
+ freed->start * kMemoryAlign, freed->size * kMemoryAlign);
+
+ return freed;
+ }
+ cur = cur->next;
+ }
+ return 0;
+}
+
+void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
+{
+ String8 result;
+ dump_l(result, what, flags);
+ LOGD("%s", result.string());
+}
+
+void SimpleBestFitAllocator::dump(String8& result,
+ const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(result, what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(String8& result,
+ const char* what, uint32_t flags) const
+{
+ size_t size = 0;
+ int32_t i = 0;
+ chunk_t const* cur = mList.head();
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
+ what, this, (unsigned int)mHeapSize);
+
+ result.append(buffer);
+
+ while (cur) {
+ const char* errs[] = {"", "| link bogus NP",
+ "| link bogus PN", "| link bogus NP+PN" };
+ int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
+ int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
+
+ snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
+ i, int(cur), int(cur->start*kMemoryAlign),
+ int(cur->size*kMemoryAlign),
+ int(cur->free) ? "F" : "A",
+ errs[np|pn]);
+
+ result.append(buffer);
+
+ if (!cur->free)
+ size += cur->size*kMemoryAlign;
+
+ i++;
+ cur = cur->next;
+ }
+ snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
+ result.append(buffer);
+}
+
+// ----------------------------------------------------------------------------
+
+SharedHeap::SharedHeap()
+ : HeapInterface(), MemoryHeapBase()
+{
+}
+
+SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
+ : MemoryHeapBase(size, flags, name)
+{
+}
+
+SharedHeap::~SharedHeap()
+{
+}
+
+sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
+{
+ return new SimpleMemory(this, offset, size);
+}
+
+
+SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
+ ssize_t offset, size_t size)
+ : MemoryBase(heap, offset, size)
+{
+#ifndef NDEBUG
+ void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
+ memset(start_ptr, 0xda, size);
+#endif
+}
+
+SimpleMemory::~SimpleMemory()
+{
+ size_t freedOffset = getOffset();
+ size_t freedSize = getSize();
+
+ // keep the size to unmap in excess
+ size_t pagesize = getpagesize();
+ size_t start = freedOffset;
+ size_t end = start + freedSize;
+ start &= ~(pagesize-1);
+ end = (end + pagesize-1) & ~(pagesize-1);
+
+ // give back to the kernel the pages we don't need
+ size_t free_start = freedOffset;
+ size_t free_end = free_start + freedSize;
+ if (start < free_start)
+ start = free_start;
+ if (end > free_end)
+ end = free_end;
+ start = (start + pagesize-1) & ~(pagesize-1);
+ end &= ~(pagesize-1);
+
+ if (start < end) {
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
+ size_t size = end-start;
+
+#ifndef NDEBUG
+ memset(start_ptr, 0xdf, size);
+#endif
+
+ // MADV_REMOVE is not defined on Dapper based Goobuntu
+#ifdef MADV_REMOVE
+ if (size) {
+ int err = madvise(start_ptr, size, MADV_REMOVE);
+ LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
+ start_ptr, size, err<0 ? strerror(errno) : "Ok");
+ }
+#endif
+ }
+}
+
+}; // namespace android
diff --git a/libs/binder/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
index 16e92f9..5cc60f8 100644
--- a/libs/binder/MemoryHeapPmem.cpp
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -127,7 +127,11 @@ void SubRegionMemory::revoke()
MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
uint32_t flags)
+#ifdef USE_ECLAIR_MEMORYDEALER
+ : HeapInterface(), MemoryHeapBase()
+#else
: MemoryHeapBase()
+#endif
{
char const * const device = pmemHeap->getDevice();
#if HAVE_ANDROID_OS
diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk
index 03ff229..3691bde 100644
--- a/libs/camera/Android.mk
+++ b/libs/camera/Android.mk
@@ -8,6 +8,10 @@ LOCAL_SRC_FILES:= \
ICameraClient.cpp \
ICameraService.cpp
+LOCAL_MODULE:= libcamera_client
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
@@ -16,10 +20,14 @@ LOCAL_SHARED_LIBRARIES := \
libsurfaceflinger_client \
libui
-LOCAL_MODULE:= libcamera_client
-
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_LDLIBS += -lpthread
endif
include $(BUILD_SHARED_LIBRARY)
+
+else
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 65fd7ac..12b08f0 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -130,6 +130,8 @@ const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+const char CameraParameters::PIXEL_FORMAT_RAW[] = "raw";
+
// Values for focus mode settings.
const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
@@ -137,6 +139,51 @@ const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
+const char CameraParameters::FOCUS_MODE_NORMAL[] = "normal";
+
+
+const char CameraParameters::KEY_SUPPORTED_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
+const char CameraParameters::KEY_GPS_LATITUDE_REF[] = "gps-latitude-ref";
+const char CameraParameters::KEY_GPS_LONGITUDE_REF[] = "gps-longitude-ref";
+const char CameraParameters::KEY_GPS_ALTITUDE_REF[] = "gps-altitude-ref";
+const char CameraParameters::KEY_GPS_STATUS[] = "gps-status";
+
+const char CameraParameters::KEY_EXIF_DATETIME[] = "exif-datetime";
+const char CameraParameters::KEY_AUTO_EXPOSURE[] = "auto-exposure";
+const char CameraParameters::KEY_SUPPORTED_AUTO_EXPOSURE[] = "auto-exposure-values";
+
+const char CameraParameters::KEY_ISO_MODE[] = "iso";
+const char CameraParameters::KEY_SUPPORTED_ISO_MODES[] = "iso-values";
+const char CameraParameters::KEY_LENSSHADE[] = "lensshade";
+const char CameraParameters::KEY_SUPPORTED_LENSSHADE_MODES[] = "lensshade-values";
+const char CameraParameters::KEY_SHARPNESS[] = "sharpness";
+const char CameraParameters::KEY_MAX_SHARPNESS[] = "max-sharpness";
+const char CameraParameters::KEY_CONTRAST[] = "contrast";
+const char CameraParameters::KEY_MAX_CONTRAST[] = "max-contrast";
+const char CameraParameters::KEY_SATURATION[] = "saturation";
+const char CameraParameters::KEY_MAX_SATURATION[] = "max-saturation";
+
+
+// Values for auto exposure settings.
+const char CameraParameters::AUTO_EXPOSURE_FRAME_AVG[] = "frame-average";
+const char CameraParameters::AUTO_EXPOSURE_CENTER_WEIGHTED[] = "center-weighted";
+const char CameraParameters::AUTO_EXPOSURE_SPOT_METERING[] = "spot-metering";
+
+ // Values for ISO Settings
+const char CameraParameters::ISO_AUTO[] = "auto";
+const char CameraParameters::ISO_HJR[] = "ISO_HJR";
+const char CameraParameters::ISO_100[] = "ISO100";
+const char CameraParameters::ISO_200[] = "ISO200";
+const char CameraParameters::ISO_400[] = "ISO400";
+const char CameraParameters::ISO_800[] = "ISO800";
+const char CameraParameters::ISO_1600[] = "ISO1600";
+
+ //Values for Lens Shading
+const char CameraParameters::LENSSHADE_ENABLE[] = "enable";
+const char CameraParameters::LENSSHADE_DISABLE[] = "disable";
+
+static const char* portrait = "portrait";
+static const char* landscape = "landscape";
CameraParameters::CameraParameters()
: mMap()
@@ -315,6 +362,23 @@ void CameraParameters::setPreviewFormat(const char *format)
set(KEY_PREVIEW_FORMAT, format);
}
+int CameraParameters::getOrientation() const
+{
+ const char* orientation = get("orientation");
+ if (orientation && !strcmp(orientation, portrait))
+ return CAMERA_ORIENTATION_PORTRAIT;
+ return CAMERA_ORIENTATION_LANDSCAPE;
+}
+
+void CameraParameters::setOrientation(int orientation)
+{
+ if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
+ set("orientation", portrait);
+ } else {
+ set("orientation", landscape);
+ }
+}
+
const char *CameraParameters::getPreviewFormat() const
{
return get(KEY_PREVIEW_FORMAT);
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 86eb78d..bf74089 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -38,8 +38,12 @@ LOCAL_SHARED_LIBRARIES := \
libEGL \
libGLESv1_CM \
libbinder \
- libui \
- libsurfaceflinger_client
+ libui
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client
+endif
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index ce7e9aa..2c7b4af 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -133,10 +133,14 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
mNoEGLImageForSwBuffers = !(hwFlags & DisplayHardware::CACHED_BUFFERS);
- // we use the red index
- int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
- int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
- mNeedsDithering = layerRedsize > displayRedSize;
+ if (mFlinger->getUseDithering()) {
+ // we use the red index
+ int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
+ int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
+ mNeedsDithering = layerRedsize > displayRedSize;
+ } else {
+ mNeedsDithering = false;
+ }
for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
mBuffers[i] = new GraphicBuffer();
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index a8b735e..046c7c3 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -33,6 +33,15 @@
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+#define RENDER_EFFECT_NIGHT 1
+#define RENDER_EFFECT_TERMINAL 2
+#define RENDER_EFFECT_BLUE 3
+#define RENDER_EFFECT_AMBER 4
+#define RENDER_EFFECT_SALMON 5
+#define RENDER_EFFECT_FUSCIA 6
+#define RENDER_EFFECT_N1_CALIBRATED_N 7
+#define RENDER_EFFECT_N1_CALIBRATED_R 8
+#define RENDER_EFFECT_N1_CALIBRATED_C 9
namespace android {
@@ -401,7 +410,14 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glEnable(GL_TEXTURE_2D);
- if (UNLIKELY(s.alpha < 0xFF)) {
+ int renderEffect = mFlinger->getRenderEffect();
+ int renderColorR = mFlinger->getRenderColorR();
+ int renderColorG = mFlinger->getRenderColorG();
+ int renderColorB = mFlinger->getRenderColorB();
+
+ bool noEffect = renderEffect == 0;
+
+ if (UNLIKELY(s.alpha < 0xFF) && noEffect) {
// We have an alpha-modulation. We need to modulate all
// texture components by alpha because we're always using
// premultiplied alpha.
@@ -423,7 +439,7 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
- } else {
+ } else if (noEffect) {
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
if (needsBlending()) {
@@ -433,6 +449,44 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
} else {
glDisable(GL_BLEND);
}
+ } else {
+ // Apply a render effect, which is simple color masks for now.
+ GLenum env, src;
+ env = GL_MODULATE;
+ src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ switch (renderEffect) {
+ case RENDER_EFFECT_NIGHT:
+ glColor4x(alpha, 0, 0, alpha);
+ break;
+ case RENDER_EFFECT_TERMINAL:
+ glColor4x(0, alpha, 0, alpha);
+ break;
+ case RENDER_EFFECT_BLUE:
+ glColor4x(0, 0, alpha, alpha);
+ break;
+ case RENDER_EFFECT_AMBER:
+ glColor4x(alpha, alpha*0.75, 0, alpha);
+ break;
+ case RENDER_EFFECT_SALMON:
+ glColor4x(alpha, alpha*0.5, alpha*0.5, alpha);
+ break;
+ case RENDER_EFFECT_FUSCIA:
+ glColor4x(alpha, 0, alpha*0.5, alpha);
+ break;
+ case RENDER_EFFECT_N1_CALIBRATED_N:
+ glColor4x(alpha*renderColorR/1000, alpha*renderColorG/1000, alpha*renderColorB/1000, alpha);
+ break;
+ case RENDER_EFFECT_N1_CALIBRATED_R:
+ glColor4x(alpha*(renderColorR-50)/1000, alpha*renderColorG/1000, alpha*(renderColorB-30)/1000, alpha);
+ break;
+ case RENDER_EFFECT_N1_CALIBRATED_C:
+ glColor4x(alpha*renderColorR/1000, alpha*renderColorG/1000, alpha*(renderColorB+30)/1000, alpha);
+ break;
+ }
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
}
Region::const_iterator it = clip.begin();
@@ -826,4 +880,4 @@ sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
// ---------------------------------------------------------------------------
-}; // namespace android
+}; // namespace android \ No newline at end of file
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 0722fda..9e327ec 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -184,13 +184,18 @@ SurfaceFlinger::SurfaceFlinger()
mFreezeDisplayTime(0),
mDebugRegion(0),
mDebugBackground(0),
+ mRenderEffect(0),
+ mRenderColorR(0),
+ mRenderColorG(0),
+ mRenderColorB(0),
mDebugInSwapBuffers(0),
mLastSwapBufferTime(0),
mDebugInTransaction(0),
mLastTransactionTime(0),
mBootFinished(false),
mConsoleSignals(0),
- mSecureFrameBuffer(0)
+ mSecureFrameBuffer(0),
+ mUseDithering(true)
{
init();
}
@@ -205,9 +210,23 @@ void SurfaceFlinger::init()
mDebugRegion = atoi(value);
property_get("debug.sf.showbackground", value, "0");
mDebugBackground = atoi(value);
+ property_get("debug.sf.render_effect", value, "0");
+ mRenderEffect = atoi(value);
+
+ // default calibration color set (disabled by default)
+ property_get("debug.sf.render_color_red", value, "975");
+ mRenderColorR = atoi(value);
+ property_get("debug.sf.render_color_green", value, "937");
+ mRenderColorG = atoi(value);
+ property_get("debug.sf.render_color_blue", value, "824");
+ mRenderColorB = atoi(value);
+
+ property_get("persist.sys.use_dithering", value, "1");
+ mUseDithering = atoi(value) == 1;
LOGI_IF(mDebugRegion, "showupdates enabled");
LOGI_IF(mDebugBackground, "showbackground enabled");
+ LOGI_IF(mUseDithering, "dithering enabled");
}
SurfaceFlinger::~SurfaceFlinger()
@@ -1692,12 +1711,30 @@ status_t SurfaceFlinger::onTransact(
reply->writeInt32(0);
reply->writeInt32(mDebugRegion);
reply->writeInt32(mDebugBackground);
+ reply->writeInt32(mRenderEffect);
return NO_ERROR;
case 1013: {
Mutex::Autolock _l(mStateLock);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
reply->writeInt32(hw.getPageFlipCount());
}
+ case 1014: { // RENDER_EFFECT
+ // TODO: filter to only allow valid effects
+ mRenderEffect = data.readInt32();
+ return NO_ERROR;
+ }
+ case 1015: { // RENDER_COLOR_RED
+ mRenderColorR = data.readInt32();
+ return NO_ERROR;
+ }
+ case 1016: { // RENDER_COLOR_GREEN
+ mRenderColorG = data.readInt32();
+ return NO_ERROR;
+ }
+ case 1017: { // RENDER_COLOR_BLUE
+ mRenderColorB = data.readInt32();
+ return NO_ERROR;
+ }
return NO_ERROR;
}
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index d75dc15..1bfdb1b 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -174,6 +174,12 @@ public:
overlay_control_device_t* getOverlayEngine() const;
+ inline int getRenderEffect() const { return mRenderEffect; }
+ inline int getRenderColorR() const { return mRenderColorR; }
+ inline int getRenderColorG() const { return mRenderColorG; }
+ inline int getRenderColorB() const { return mRenderColorB; }
+ inline int getUseDithering() const { return mUseDithering; }
+
status_t removeLayer(const sp<LayerBase>& layer);
status_t addLayer(const sp<LayerBase>& layer);
@@ -354,6 +360,10 @@ private:
// don't use a lock for these, we don't care
int mDebugRegion;
int mDebugBackground;
+ int mRenderEffect;
+ int mRenderColorR;
+ int mRenderColorG;
+ int mRenderColorB;
volatile nsecs_t mDebugInSwapBuffers;
nsecs_t mLastSwapBufferTime;
volatile nsecs_t mDebugInTransaction;
@@ -372,6 +382,7 @@ private:
// only written in the main thread, only read in other threads
volatile int32_t mSecureFrameBuffer;
+ bool mUseDithering;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk
index fe85b34..5368280 100644
--- a/libs/surfaceflinger_client/Android.mk
+++ b/libs/surfaceflinger_client/Android.mk
@@ -10,6 +10,10 @@ LOCAL_SRC_FILES:= \
Surface.cpp \
SurfaceComposerClient.cpp
+LOCAL_MODULE:= libsurfaceflinger_client
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
@@ -17,10 +21,15 @@ LOCAL_SHARED_LIBRARIES := \
libhardware \
libui
-LOCAL_MODULE:= libsurfaceflinger_client
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_LDLIBS += -lpthread
endif
include $(BUILD_SHARED_LIBRARY)
+
+else
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index f7acd97..c5bc8bd 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -26,6 +26,27 @@ LOCAL_SHARED_LIBRARIES := \
libhardware \
libhardware_legacy
+
+ifeq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+
+LOCAL_SRC_FILES+= \
+ ../camera/Camera.cpp \
+ ../camera/CameraParameters.cpp \
+ ../camera/ICamera.cpp \
+ ../camera/ICameraClient.cpp \
+ ../camera/ICameraService.cpp
+
+LOCAL_SRC_FILES+= \
+ ../surfaceflinger_client/ISurfaceComposer.cpp \
+ ../surfaceflinger_client/ISurface.cpp \
+ ../surfaceflinger_client/ISurfaceFlingerClient.cpp \
+ ../surfaceflinger_client/LayerState.cpp \
+ ../surfaceflinger_client/SharedBufferStack.cpp \
+ ../surfaceflinger_client/Surface.cpp \
+ ../surfaceflinger_client/SurfaceComposerClient.cpp
+
+endif
+
LOCAL_MODULE:= libui
ifeq ($(TARGET_SIMULATOR),true)
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index d45eaf0..0a98cb2 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -642,7 +642,10 @@ int EventHub::open_device(const char *deviceName)
if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
{
if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
- device->classes |= CLASS_TRACKBALL;
+ if (test_bit(BTN_LEFT, key_bitmask) && test_bit(BTN_RIGHT, key_bitmask))
+ device->classes |= CLASS_MOUSE;
+ else
+ device->classes |= CLASS_TRACKBALL;
}
}
}
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
index 3aa8950..96f8006 100644
--- a/libs/ui/Overlay.cpp
+++ b/libs/ui/Overlay.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,6 +84,12 @@ status_t Overlay::getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
return mOverlayData->getCrop(mOverlayData, x, y, w, h);
}
+status_t Overlay::setFd(int fd)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setFd(mOverlayData, fd);
+}
+
int32_t Overlay::getBufferCount() const
{
if (mStatus != NO_ERROR) return mStatus;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 7e0f881..1a40deb 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -4393,7 +4393,6 @@ void ResTable::print(bool inclValues) const
}
printf("\n");
- if (inclValues) {
if (valuePtr != NULL) {
printf(" ");
print_value(pkg, value);
@@ -4413,7 +4412,6 @@ void ResTable::print(bool inclValues) const
+ size + sizeof(*mapPtr)-sizeof(mapPtr->value));
}
}
- }
}
}
}
diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java
index ac275c6..b152f48 100644
--- a/location/java/android/location/Address.java
+++ b/location/java/android/location/Address.java
@@ -500,7 +500,10 @@ public class Address implements Parcelable {
a.mAdminArea = in.readString();
a.mSubAdminArea = in.readString();
a.mLocality = in.readString();
+ a.mSubLocality = in.readString();
a.mThoroughfare = in.readString();
+ a.mSubThoroughfare = in.readString();
+ a.mPremises = in.readString();
a.mPostalCode = in.readString();
a.mCountryCode = in.readString();
a.mCountryName = in.readString();
@@ -544,7 +547,10 @@ public class Address implements Parcelable {
parcel.writeString(mAdminArea);
parcel.writeString(mSubAdminArea);
parcel.writeString(mLocality);
+ parcel.writeString(mSubLocality);
parcel.writeString(mThoroughfare);
+ parcel.writeString(mSubThoroughfare);
+ parcel.writeString(mPremises);
parcel.writeString(mPostalCode);
parcel.writeString(mCountryCode);
parcel.writeString(mCountryName);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bbbba74..1cd8fd0 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1215,6 +1215,13 @@ public class AudioManager {
return Settings.System.getInt(mContext.getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0;
}
+ /**
+ * See if haptic feedback is enabled for screen touches of objects (called by ViewRoot)
+ * @hide
+ */
+ public boolean queryHapticsAllEnabled() {
+ return Settings.System.getInt(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ALL_ENABLED, 0) != 0;
+ }
/**
* Load Sound effects.
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 64d6460..5915494 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -48,12 +48,16 @@ public class CamcorderProfile
* resolution and higher audio sampling rate, etc, than those with low quality
* level.
*
+ * An optional profile, "front" is defined as a high quality profile for devices
+ * with a front-facing camera.
+ *
* Do not change these values/ordinals without updating their counterpart
* in include/media/MediaProfiles.h!
*/
public static final int QUALITY_LOW = 0;
public static final int QUALITY_HIGH = 1;
-
+ public static final int QUALITY_FRONT = 2;
+
/**
* Default recording duration in seconds before the session is terminated.
* This is useful for applications like MMS has limited file size requirement.
@@ -123,7 +127,7 @@ public class CamcorderProfile
* @param quality the target quality level for the camcorder profile
*/
public static CamcorderProfile get(int quality) {
- if (quality < QUALITY_LOW || quality > QUALITY_HIGH) {
+ if (quality < QUALITY_LOW || quality > QUALITY_FRONT) {
String errMessage = "Unsupported quality level: " + quality;
throw new IllegalArgumentException(errMessage);
}
diff --git a/media/java/android/media/EncoderCapabilities.java b/media/java/android/media/EncoderCapabilities.java
index 71cb1b3..1f285bb 100644
--- a/media/java/android/media/EncoderCapabilities.java
+++ b/media/java/android/media/EncoderCapabilities.java
@@ -24,7 +24,6 @@ import android.util.Log;
* The EncoderCapabilities class is used to retrieve the
* capabilities for different video and audio
* encoders supported on a specific Android platform.
- * {@hide}
*/
public class EncoderCapabilities
{
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 9d1d420..aece959 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -46,8 +46,9 @@ public class MediaFile {
public static final int FILE_TYPE_WMA = 6;
public static final int FILE_TYPE_OGG = 7;
public static final int FILE_TYPE_AAC = 8;
+ public static final int FILE_TYPE_FLAC = 9;
private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3;
- private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_AAC;
+ private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_FLAC;
// MIDI file types
public static final int FILE_TYPE_MID = 11;
@@ -134,6 +135,7 @@ public class MediaFile {
addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
addFileType("OGA", FILE_TYPE_OGG, "application/ogg");
addFileType("AAC", FILE_TYPE_AAC, "audio/aac");
+ addFileType("FLAC", FILE_TYPE_FLAC, "audio/flac");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
addFileType("MIDI", FILE_TYPE_MID, "audio/midi");
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 47a8cfc..646dfbb 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -204,7 +204,7 @@ public class MediaRecorder
public static final int AMR_NB = 1;
/** @hide AMR (Wideband) audio codec */
public static final int AMR_WB = 2;
- /** @hide AAC audio codec */
+ /** AAC audio codec */
public static final int AAC = 3;
/** @hide enhanced AAC audio codec */
public static final int AAC_PLUS = 4;
@@ -259,6 +259,9 @@ public class MediaRecorder
public native void setVideoSource(int video_source)
throws IllegalStateException;
+ public native void setCameraParameters(String params)
+ throws IllegalStateException;
+
/**
* Uses the settings from a CamcorderProfile object for recording. This method should
* be called after the video AND audio sources are set, and before setOutputFile().
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 0ce3526..0cecc3f 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -166,6 +166,9 @@ public class Ringtone {
}
private void openMediaPlayer() throws IOException {
+ if (mAudio != null) {
+ return;
+ }
mAudio = new MediaPlayer();
if (mUri != null) {
mAudio.setDataSource(mContext, mUri);
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a6a25cd..29bb027 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -21,9 +21,13 @@ LOCAL_SHARED_LIBRARIES := \
libmedia \
libskia \
libui \
- libcutils \
- libsurfaceflinger_client \
- libcamera_client
+ libcutils
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client \
+ libcamera_client
+endif
ifneq ($(BUILD_WITHOUT_PV),true)
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index 7d7533a..ff3379e 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -165,7 +165,7 @@ static jobject
android_media_MediaProfiles_native_get_camcorder_profile(JNIEnv *env, jobject thiz, jint quality)
{
LOGV("native_get_camcorder_profile: %d", quality);
- if (quality != CAMCORDER_QUALITY_HIGH && quality != CAMCORDER_QUALITY_LOW) {
+ if (quality != CAMCORDER_QUALITY_HIGH && quality != CAMCORDER_QUALITY_LOW && quality != CAMCORDER_QUALITY_FRONT) {
jniThrowException(env, "java/lang/RuntimeException", "Unknown camcorder profile quality");
return NULL;
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 00af3a2..35e1d64 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -246,6 +246,29 @@ android_media_MediaRecorder_setParameter(JNIEnv *env, jobject thiz, jstring para
}
static void
+android_media_MediaRecorder_setCameraParameters(JNIEnv *env, jobject thiz, jstring params)
+{
+ LOGV("setCameraParameters()");
+ if (params == NULL)
+ {
+ LOGE("Invalid or empty params string. This parameter will be ignored.");
+ return;
+ }
+
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+
+ const char* params8 = env->GetStringUTFChars(params, NULL);
+ if (params8 == NULL)
+ {
+ LOGE("Failed to covert jstring to String8. This parameter will be ignored.");
+ return;
+ }
+
+ process_media_recorder_call(env, mr->setCameraParameters(String8(params8)), "java/lang/RuntimeException", "setCameraParameters failed.");
+ env->ReleaseStringUTFChars(params,params8);
+}
+
+static void
android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
LOGV("setOutputFile");
@@ -456,6 +479,7 @@ static JNINativeMethod gMethods[] = {
{"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder},
{"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder},
{"setParameter", "(Ljava/lang/String;)V", (void *)android_media_MediaRecorder_setParameter},
+ {"setCameraParameters", "(Ljava/lang/String;)V", (void *)android_media_MediaRecorder_setCameraParameters},
{"_setOutputFile", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaRecorder_setOutputFileFD},
{"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize},
{"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate},
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 3adabcc..02b8324 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -29,7 +29,13 @@ LOCAL_SRC_FILES:= \
MediaProfiles.cpp
LOCAL_SHARED_LIBRARIES := \
- libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client
+ libui libcutils libutils libbinder libsonivox libicuuc libexpat
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client \
+ libcamera_client
+endif
LOCAL_MODULE:= libmedia
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index ad037d6..4e38773 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -37,6 +37,10 @@
#include <utils/Timers.h>
#include <cutils/atomic.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
+#include <binder/MemoryDealer.h>
+#endif
+
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index cd7bcd5..ba99d81 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -37,6 +37,10 @@
#include <utils/Timers.h>
#include <cutils/atomic.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
+#include <binder/MemoryDealer.h>
+#endif
+
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 1de9f9b..11ca90c 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -45,6 +45,7 @@ enum {
SET_VIDEO_SIZE,
SET_VIDEO_FRAMERATE,
SET_PARAMETERS,
+ SET_CAMERA_PARAMETERS,
SET_PREVIEW_SURFACE,
SET_CAMERA,
SET_LISTENER
@@ -189,6 +190,16 @@ public:
return reply.readInt32();
}
+ status_t setCameraParameters(const String8& params)
+ {
+ LOGV("setCameraParameter(%s)", params.string());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeString8(params);
+ remote()->transact(SET_CAMERA_PARAMETERS, data, &reply);
+ return reply.readInt32();
+ }
+
status_t setListener(const sp<IMediaPlayerClient>& listener)
{
LOGV("setListener(%p)", listener.get());
@@ -396,6 +407,12 @@ status_t BnMediaRecorder::onTransact(
reply->writeInt32(setParameters(data.readString8()));
return NO_ERROR;
} break;
+ case SET_CAMERA_PARAMETERS: {
+ LOGV("SET_CAMERA_PARAMETER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(setCameraParameters(data.readString8()));
+ return NO_ERROR;
+ } break;
case SET_LISTENER: {
LOGV("SET_LISTENER");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 1263373..1b3be41 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -59,8 +59,9 @@ const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
};
const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
- {"high", CAMCORDER_QUALITY_HIGH},
- {"low", CAMCORDER_QUALITY_LOW}
+ {"high", CAMCORDER_QUALITY_HIGH},
+ {"low", CAMCORDER_QUALITY_LOW},
+ {"front", CAMCORDER_QUALITY_FRONT}
};
/*static*/ void
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 5adc116..bfa4b2b 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -385,6 +385,28 @@ status_t MediaRecorder::setParameters(const String8& params) {
return ret;
}
+status_t MediaRecorder::setCameraParameters(const String8& params) {
+ LOGV("setCameraParameters(%s)", params.string());
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+
+ bool isInvalidState = (mCurrentState &
+ MEDIA_RECORDER_ERROR);
+ if (isInvalidState) {
+ LOGE("setCameraParameters is called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setCameraParameters(params);
+ if (OK != ret) {
+ LOGE("setCameraParameters(%s) failed: %d", params.string(), ret);
+ }
+
+ return ret;
+}
+
status_t MediaRecorder::prepare()
{
LOGV("prepare");
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index cf97b23..ecd1d2e 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -13,7 +13,8 @@ LOCAL_SRC_FILES:= \
TestPlayerStub.cpp \
VorbisPlayer.cpp \
VorbisMetadataRetriever.cpp \
- MidiMetadataRetriever.cpp \
+ FLACPlayer.cpp \
+ MidiMetadataRetriever.cpp \
MidiFile.cpp
ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
@@ -40,12 +41,17 @@ LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
libstagefright \
libstagefright_omx \
- libstagefright_color_conversion \
- libsurfaceflinger_client
+ libstagefright_color_conversion
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client
+endif
ifneq ($(BUILD_WITHOUT_PV),true)
LOCAL_SHARED_LIBRARIES += \
libopencore_player \
+ libFLAC \
libopencore_author
else
LOCAL_CFLAGS += -DNO_OPENCORE
@@ -56,6 +62,7 @@ LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_C_INCLUDES := \
+ external/flac/include \
$(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
diff --git a/media/libmediaplayerservice/FLACPlayer.cpp b/media/libmediaplayerservice/FLACPlayer.cpp
new file mode 100644
index 0000000..1f8e3b6
--- /dev/null
+++ b/media/libmediaplayerservice/FLACPlayer.cpp
@@ -0,0 +1,577 @@
+/*
+** 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FLACPlayer"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+#include "FLACPlayer.h"
+
+#ifdef HAVE_GETTID
+static pid_t myTid() { return gettid(); }
+#else
+static pid_t myTid() { return getpid(); }
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// TODO: Determine appropriate return codes
+static status_t ERROR_NOT_OPEN = -1;
+static status_t ERROR_OPEN_FAILED = -2;
+static status_t ERROR_ALLOCATE_FAILED = -4;
+static status_t ERROR_NOT_SUPPORTED = -8;
+static status_t ERROR_NOT_READY = -16;
+static status_t STATE_INIT = 0;
+static status_t STATE_ERROR = 1;
+static status_t STATE_OPEN = 2;
+
+
+FLACPlayer::FLACPlayer() :
+ mTotalSamples(-1), mCurrentSample(0), mBytesPerSample(-1),
+ mChannels(-1), mSampleRate(-1), mAudioBuffer(NULL),
+ mAudioBufferSize(0), mAudioBufferFilled(0),
+ mState(STATE_ERROR), mStreamType(AudioSystem::MUSIC),
+ mLoop(false), mAndroidLoop(false), mExit(false), mPaused(false),
+ mRender(false), mRenderTid(-1)
+{
+ LOGV("constructor");
+}
+
+void FLACPlayer::onFirstRef()
+{
+ LOGV("onFirstRef");
+ // create playback thread
+ Mutex::Autolock l(mMutex);
+ createThreadEtc(renderThread, this, "FLAC decoder", ANDROID_PRIORITY_AUDIO);
+ mCondition.wait(mMutex);
+ if (mRenderTid > 0) {
+ LOGV("render thread(%d) started", mRenderTid);
+ mState = STATE_INIT;
+ }
+}
+
+status_t FLACPlayer::initCheck()
+{
+ if (mState != STATE_ERROR) return NO_ERROR;
+ return ERROR_NOT_READY;
+}
+
+FLACPlayer::~FLACPlayer() {
+ LOGV("FLACPlayer destructor");
+ release();
+}
+
+status_t FLACPlayer::setDataSource(
+ const char *uri, const KeyedVector<String8, String8> *headers) {
+ return setdatasource(uri, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX
+}
+
+status_t FLACPlayer::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ return setdatasource(NULL, fd, offset, length);
+}
+
+status_t FLACPlayer::setdatasource(const char *path, int fd, int64_t offset, int64_t length)
+{
+ LOGV("setDataSource url=%s, fd=%d", path, fd);
+
+ // file still open?
+ Mutex::Autolock l(mMutex);
+ if (mState == STATE_OPEN) {
+ reset_nosync();
+ }
+
+ // open file and set paused state
+ if (path) {
+ mFile = fopen(path, "r");
+ } else {
+ mFile = fdopen(dup(fd), "r");
+ }
+ if (mFile == NULL) {
+ return ERROR_OPEN_FAILED;
+ }
+
+ struct stat sb;
+ int ret;
+ if (path) {
+ ret = stat(path, &sb);
+ } else {
+ ret = fstat(fd, &sb);
+ }
+ if (ret != 0) {
+ mState = STATE_ERROR;
+ fclose(mFile);
+ return ERROR_OPEN_FAILED;
+ }
+
+ fseek(mFile, offset, SEEK_SET);
+
+ mDecoder = FLAC__stream_decoder_new();
+ if (mDecoder == NULL) {
+ LOGE("failed to allocate decoder\n");
+ mState = STATE_ERROR;
+ fclose(mFile);
+ return ERROR_OPEN_FAILED;
+ }
+
+ FLAC__stream_decoder_set_md5_checking(mDecoder, false);
+ FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
+ FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_STREAMINFO);
+ FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ FLAC__StreamDecoderInitStatus init_status;
+ init_status = FLAC__stream_decoder_init_FILE(mDecoder, mFile, vp_write, vp_metadata, vp_error, this);
+ if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ LOGE("FLAC__stream_decoder_init_FILE failed: [%d]\n", (int)init_status);
+ mState = STATE_ERROR;
+ fclose(mFile);
+ return ERROR_OPEN_FAILED;
+ }
+
+ if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
+ LOGE("FLAC__stream_decoder_process_until_end_of_metadata failed\n");
+ mState = STATE_ERROR;
+ fclose(mFile);
+ return ERROR_OPEN_FAILED;
+ }
+
+ mState = STATE_OPEN;
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::prepare()
+{
+ LOGV("prepare");
+ if (mState != STATE_OPEN ) {
+ return ERROR_NOT_OPEN;
+ }
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::prepareAsync() {
+ LOGV("prepareAsync");
+ // can't hold the lock here because of the callback
+ // it's safe because we don't change state
+ if (mState != STATE_OPEN) {
+ sendEvent(MEDIA_ERROR);
+ return NO_ERROR;
+ }
+ sendEvent(MEDIA_PREPARED);
+ return NO_ERROR;
+}
+
+void FLACPlayer::vp_metadata(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) {
+ FLACPlayer *self = (FLACPlayer *)client_data;
+
+ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ self->mTotalSamples = metadata->data.stream_info.total_samples;
+ self->mBytesPerSample = metadata->data.stream_info.bits_per_sample / 8;
+ self->mChannels = metadata->data.stream_info.channels;
+ self->mSampleRate = metadata->data.stream_info.sample_rate;
+
+ if (self->mBytesPerSample != 2) {
+ LOGE("Can only support 16 bits per sample; input is %d\n", self->mBytesPerSample * 8);
+ self->mState = STATE_ERROR;
+ return;
+ }
+
+ self->mLengthInMsec = self->mTotalSamples / self->mSampleRate * 1000 +
+ self->mTotalSamples % self->mSampleRate / ( self->mSampleRate / 1000 );
+ } else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+ for (unsigned int i = 0; i < metadata->data.vorbis_comment.num_comments; i++) {
+ char *ptr = (char *)metadata->data.vorbis_comment.comments[i].entry;
+
+ // does the comment start with ANDROID_LOOP_TAG
+ if (strncmp(ptr, ANDROID_LOOP_TAG, strlen(ANDROID_LOOP_TAG)) == 0) {
+ // read the value of the tag
+ char *val = ptr + strlen(ANDROID_LOOP_TAG) + 1;
+ self->mAndroidLoop = (strncmp(val, "true", 4) == 0);
+ }
+
+ LOGV_IF(self->mAndroidLoop, "looped sound");
+ }
+ }
+}
+
+void FLACPlayer::vp_error(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) {
+ LOGV("vp_error");
+ FLACPlayer *self = (FLACPlayer *)client_data;
+ self->sendEvent(MEDIA_ERROR);
+ self->mState = STATE_ERROR;
+}
+
+status_t FLACPlayer::start()
+{
+ LOGV("start\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+
+ mPaused = false;
+ mRender = true;
+
+ // wake up render thread
+ LOGV(" wakeup render thread\n");
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::stop()
+{
+ LOGV("stop\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+ mPaused = true;
+ mRender = false;
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::seekTo(int msec)
+{
+ LOGV("seekTo %d\n", msec);
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+
+ FLAC__uint64 target_sample = mTotalSamples * msec / mLengthInMsec;
+
+ if (mTotalSamples > 0 && target_sample >= mTotalSamples && target_sample > 0)
+ target_sample = mTotalSamples - 1;
+
+ if (!FLAC__stream_decoder_seek_absolute(mDecoder, target_sample)) {
+ LOGE("FLAC__stream_decoder_seek_absolute failed\n");
+ if (FLAC__stream_decoder_get_state(mDecoder) == FLAC__STREAM_DECODER_SEEK_ERROR) {
+ FLAC__stream_decoder_flush(mDecoder);
+ }
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ mCurrentSample = target_sample;
+
+ sendEvent(MEDIA_SEEK_COMPLETE);
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::pause()
+{
+ LOGV("pause\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+ mPaused = true;
+ return NO_ERROR;
+}
+
+bool FLACPlayer::isPlaying()
+{
+ LOGV("isPlaying\n");
+ if (mState == STATE_OPEN) {
+ return mRender;
+ }
+ return false;
+}
+
+status_t FLACPlayer::getCurrentPosition(int* msec)
+{
+ LOGV("getCurrentPosition\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ LOGE("getCurrentPosition(): file not open");
+ return ERROR_NOT_OPEN;
+ }
+
+ *msec = (int)(mCurrentSample * 1000 / mSampleRate);
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::getDuration(int* duration)
+{
+ LOGV("getDuration\n");
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+
+ *duration = mLengthInMsec;
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::release()
+{
+ LOGV("release\n");
+ Mutex::Autolock l(mMutex);
+ reset_nosync();
+
+ // TODO: timeout when thread won't exit
+ // wait for render thread to exit
+ if (mRenderTid > 0) {
+ mExit = true;
+ mCondition.signal();
+ mCondition.wait(mMutex);
+ }
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::reset()
+{
+ LOGV("reset\n");
+ Mutex::Autolock l(mMutex);
+ return reset_nosync();
+}
+
+// always call with lock held
+status_t FLACPlayer::reset_nosync()
+{
+ // close file
+ if (mFile != NULL) {
+ FLAC__stream_decoder_delete(mDecoder);
+ fclose(mFile);
+ mFile = NULL;
+ }
+ mState = STATE_ERROR;
+
+ mTotalSamples = -1;
+ mBytesPerSample = -1;
+ mChannels = -1;
+ mSampleRate = -1;
+ mLoop = false;
+ mAndroidLoop = false;
+ mPaused = false;
+ mRender = false;
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::setLooping(int loop)
+{
+ LOGV("setLooping\n");
+ Mutex::Autolock l(mMutex);
+ mLoop = (loop != 0);
+ return NO_ERROR;
+}
+
+status_t FLACPlayer::createOutputTrack() {
+ LOGV("Create AudioTrack object: rate=%ld, channels=%d\n",
+ mSampleRate, mChannels);
+ if (mAudioSink->open(mSampleRate, mChannels, AudioSystem::PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT) != NO_ERROR) {
+ LOGE("mAudioSink open failed\n");
+ return ERROR_OPEN_FAILED;
+ }
+ return NO_ERROR;
+}
+
+FLAC__StreamDecoderWriteStatus FLACPlayer::vp_write(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) {
+ FLACPlayer *self = (FLACPlayer *)client_data;
+
+ const uint32_t bytes_per_sample = self->mBytesPerSample;
+ const uint32_t incr = bytes_per_sample * self->mChannels;
+ const uint32_t wide_samples = frame->header.blocksize;
+ const uint32_t frame_size = incr * wide_samples;
+
+ self->mCurrentSample = frame->header.number.sample_number;
+
+ uint32_t sample, wide_sample, channel;
+
+ if (self->mAudioBufferSize < frame_size) {
+ if (self->mAudioBuffer != NULL) {
+ delete [] self->mAudioBuffer;
+ }
+ self->mAudioBuffer = new FLAC__int8[frame_size];
+ self->mAudioBufferSize = frame_size;
+ }
+
+ FLAC__int8 *s8buffer = self->mAudioBuffer;
+ FLAC__int16 *s16buffer = (FLAC__int16 *)s8buffer;
+
+ // Interleave channel data like PCM
+ if (self->mChannels == 2) {
+ for (sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
+ s16buffer[sample++] = (FLAC__int16)(buffer[1][wide_sample]);
+ }
+ } else if (self->mChannels == 1) {
+ for (sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
+ }
+ } else {
+ for (sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ for (channel = 0; channel < self->mChannels; channel++, sample++) {
+ s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]);
+ }
+ }
+ }
+ self->mAudioBufferFilled = frame_size;
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+int FLACPlayer::renderThread(void* p) {
+ return ((FLACPlayer*)p)->render();
+}
+
+int FLACPlayer::render() {
+ int result = -1;
+ int temp;
+ int current_section = 0;
+ bool audioStarted = false;
+
+ LOGV("render\n");
+
+ // let main thread know we're ready
+ {
+ Mutex::Autolock l(mMutex);
+ mRenderTid = myTid();
+ mCondition.signal();
+ }
+
+ while (1) {
+ FLAC__bool status = true;
+ {
+ Mutex::Autolock l(mMutex);
+
+ // pausing?
+ if (mPaused) {
+ if (mAudioSink->ready()) mAudioSink->pause();
+ mRender = false;
+ audioStarted = false;
+ }
+
+ // nothing to render, wait for client thread to wake us up
+ if (!mExit && !mRender) {
+ LOGV("render - signal wait\n");
+ mCondition.wait(mMutex);
+ LOGV("render - signal rx'd\n");
+ }
+ if (mExit) break;
+
+ // We could end up here if start() is called, and before we get a
+ // chance to run, the app calls stop() or reset(). Re-check render
+ // flag so we don't try to render in stop or reset state.
+ if (!mRender) continue;
+
+ // create audio output track if necessary
+ if (!mAudioSink->ready()) {
+ LOGV("render - create output track\n");
+ if (createOutputTrack() != NO_ERROR)
+ break;
+ }
+
+
+ // start audio output if necessary
+ if (!audioStarted && !mPaused && !mExit) {
+ LOGV("render - starting audio\n");
+ mAudioSink->start();
+ audioStarted = true;
+ }
+
+ if (FLAC__stream_decoder_get_state(mDecoder) != FLAC__STREAM_DECODER_END_OF_STREAM) {
+ status = FLAC__stream_decoder_process_single(mDecoder);
+ } else {
+ // end of file, do we need to loop?
+ // ...
+ if (mLoop || mAndroidLoop) {
+ FLAC__stream_decoder_seek_absolute(mDecoder, 0);
+ mCurrentSample = 0;
+ status = FLAC__stream_decoder_process_single(mDecoder);
+ } else {
+ mAudioSink->stop();
+ audioStarted = false;
+ mRender = false;
+ mPaused = true;
+
+ FLAC__uint64 endpos;
+ if (!FLAC__stream_decoder_get_decode_position(mDecoder, &endpos)) {
+ endpos = 0;
+ }
+
+ LOGV("send MEDIA_PLAYBACK_COMPLETE\n");
+ sendEvent(MEDIA_PLAYBACK_COMPLETE);
+
+ // wait until we're started again
+ LOGV("playback complete - wait for signal\n");
+ mCondition.wait(mMutex);
+ LOGV("playback complete - signal rx'd\n");
+ if (mExit) break;
+
+ // if we're still at the end, restart from the beginning
+ if (mState == STATE_OPEN) {
+ FLAC__uint64 curpos;
+ if (FLAC__stream_decoder_get_decode_position(mDecoder, &curpos)) {
+ curpos = 0;
+ }
+ if (curpos == endpos) {
+ FLAC__stream_decoder_seek_absolute(mDecoder, 0);
+ mCurrentSample = 0;
+ }
+ status = FLAC__stream_decoder_process_single(mDecoder);
+ }
+ }
+ }
+ }
+
+ if (!status) {
+ LOGE("Error in FLAC decoder: %s\n", FLAC__stream_decoder_get_resolved_state_string(mDecoder));
+ sendEvent(MEDIA_ERROR);
+ break;
+ }
+
+ if (mAudioBufferFilled > 0) {
+ /* Be sure to clear mAudioBufferFilled even if there's an error. */
+ uint32_t toPlay = mAudioBufferFilled;
+ mAudioBufferFilled = 0;
+
+ if (!mAudioSink->write(mAudioBuffer, toPlay)) {
+ LOGE("Error in FLAC decoder: %s\n", FLAC__stream_decoder_get_resolved_state_string(mDecoder));
+ sendEvent(MEDIA_ERROR);
+ break;
+ }
+ }
+ }
+
+threadExit:
+ mAudioSink.clear();
+ if (mAudioBuffer != NULL) {
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
+ mAudioBufferSize = 0;
+ mAudioBufferFilled = 0;
+ }
+
+ // tell main thread goodbye
+ Mutex::Autolock l(mMutex);
+ mRenderTid = -1;
+ mCondition.signal();
+ return result;
+}
+
+} // end namespace android
diff --git a/media/libmediaplayerservice/FLACPlayer.h b/media/libmediaplayerservice/FLACPlayer.h
new file mode 100644
index 0000000..b7068c3
--- /dev/null
+++ b/media/libmediaplayerservice/FLACPlayer.h
@@ -0,0 +1,100 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_FLACPLAYER_H
+#define ANDROID_FLACPLAYER_H
+
+#include <utils/threads.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/AudioTrack.h>
+
+#include "FLAC/all.h"
+
+#define ANDROID_LOOP_TAG "ANDROID_LOOP"
+
+namespace android {
+
+class FLACPlayer : public MediaPlayerInterface {
+public:
+ FLACPlayer();
+ ~FLACPlayer();
+
+ virtual void onFirstRef();
+ virtual status_t initCheck();
+
+ virtual status_t setDataSource(
+ const char *uri, const KeyedVector<String8, String8> *headers);
+
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t seekTo(int msec);
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t getCurrentPosition(int* msec);
+ virtual status_t getDuration(int* msec);
+ virtual status_t release();
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType() { return FLAC_PLAYER; }
+ virtual status_t invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;}
+
+private:
+ status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length);
+ status_t reset_nosync();
+ status_t createOutputTrack();
+ static int renderThread(void*);
+ int render();
+
+ static void vp_metadata(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *, void *);
+ static void vp_error(const FLAC__StreamDecoder *, const FLAC__StreamDecoderErrorStatus, void *);
+ static FLAC__StreamDecoderWriteStatus
+ vp_write(const FLAC__StreamDecoder *, const FLAC__Frame *, const FLAC__int32 * const[], void *);
+
+ FLAC__uint64 mTotalSamples;
+ FLAC__uint64 mCurrentSample;
+ uint32_t mBytesPerSample;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ uint32_t mLengthInMsec;
+
+ FLAC__int8 * mAudioBuffer;
+ uint32_t mAudioBufferSize;
+ uint32_t mAudioBufferFilled;
+
+ Mutex mMutex;
+ Condition mCondition;
+ FILE* mFile;
+ FLAC__StreamDecoder* mDecoder;
+ status_t mState;
+ int mStreamType;
+ bool mLoop;
+ bool mAndroidLoop;
+ volatile bool mExit;
+ bool mPaused;
+ volatile bool mRender;
+ pid_t mRenderTid;
+};
+
+}; // namespace android
+
+#endif // ANDROID_FLACPLAYER_H
+
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3e1f4a5..911d89f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -57,6 +57,7 @@
#include "MidiFile.h"
#include "VorbisPlayer.h"
+#include "FLACPlayer.h"
#include <media/PVPlayer.h>
#include "TestPlayerStub.h"
#include "StagefrightPlayer.h"
@@ -204,6 +205,7 @@ extmap FILE_EXTS [] = {
{".wmv", PV_PLAYER},
{".asf", PV_PLAYER},
#endif
+ {".flac", FLAC_PLAYER},
};
// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
@@ -719,6 +721,9 @@ player_type getPlayerType(int fd, int64_t offset, int64_t length)
}
#endif
+ if (ident == 0x43614c66) // 'fLaC'
+ return FLAC_PLAYER;
+
// Some kind of MIDI?
EAS_DATA_HANDLE easdata;
if (EAS_Init(&easdata) == EAS_SUCCESS) {
@@ -812,6 +817,10 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
LOGV("Create Test Player stub");
p = new TestPlayerStub();
break;
+ case FLAC_PLAYER:
+ LOGV(" create FLACPlayer");
+ p = new FLACPlayer();
+ break;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 12de0d9..189d97d3 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -196,6 +196,16 @@ status_t MediaRecorderClient::setParameters(const String8& params) {
return mRecorder->setParameters(params);
}
+status_t MediaRecorderClient::setCameraParameters(const String8& params) {
+ LOGV("setCameraParameters(%s)", params.string());
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setCameraParameters(params);
+}
+
status_t MediaRecorderClient::prepare()
{
LOGV("prepare");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 805005d..4a6b9a1 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -40,6 +40,7 @@ public:
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
virtual status_t setParameters(const String8& params);
+ virtual status_t setCameraParameters(const String8& params);
virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
virtual status_t prepare();
virtual status_t getMaxAmplitude(int* max);
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 550b84d..070680e 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -28,8 +28,12 @@
#include <string.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
+#include <binder/MemoryDealer.h>
+#else
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
+#endif
#include <android_runtime/ActivityManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -63,6 +67,10 @@ MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
{
LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
mPid = pid;
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mThumbnailDealer = NULL;
+ mAlbumArtDealer = NULL;
+#endif
mThumbnail = NULL;
mAlbumArt = NULL;
mRetriever = NULL;
@@ -93,6 +101,10 @@ void MetadataRetrieverClient::disconnect()
LOGV("disconnect from pid %d", mPid);
Mutex::Autolock lock(mLock);
mRetriever.clear();
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mThumbnailDealer.clear();
+ mAlbumArtDealer.clear();
+#endif
mThumbnail.clear();
mAlbumArt.clear();
mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
@@ -239,6 +251,9 @@ sp<IMemory> MetadataRetrieverClient::captureFrame()
LOGV("captureFrame");
Mutex::Autolock lock(mLock);
mThumbnail.clear();
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mThumbnailDealer.clear();
+#endif
if (mRetriever == NULL) {
LOGE("retriever is not initialized");
return NULL;
@@ -249,15 +264,27 @@ sp<IMemory> MetadataRetrieverClient::captureFrame()
return NULL;
}
size_t size = sizeof(VideoFrame) + frame->mSize;
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mThumbnailDealer = new MemoryDealer(size);
+ if (mThumbnailDealer == NULL) {
+#else
sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
if (heap == NULL) {
+#endif
LOGE("failed to create MemoryDealer");
delete frame;
return NULL;
}
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mThumbnail = mThumbnailDealer->allocate(size);
+#else
mThumbnail = new MemoryBase(heap, 0, size);
+#endif
if (mThumbnail == NULL) {
LOGE("not enough memory for VideoFrame size=%u", size);
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mThumbnailDealer.clear();
+#endif
delete frame;
return NULL;
}
@@ -278,6 +305,9 @@ sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
LOGV("extractAlbumArt");
Mutex::Autolock lock(mLock);
mAlbumArt.clear();
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mAlbumArtDealer.clear();
+#endif
if (mRetriever == NULL) {
LOGE("retriever is not initialized");
return NULL;
@@ -288,15 +318,27 @@ sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
return NULL;
}
size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mAlbumArtDealer = new MemoryDealer(size);
+ if (mAlbumArtDealer == NULL) {
+#else
sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
if (heap == NULL) {
+#endif
LOGE("failed to create MemoryDealer object");
delete albumArt;
return NULL;
}
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mAlbumArt = mAlbumArtDealer->allocate(size);
+#else
mAlbumArt = new MemoryBase(heap, 0, size);
+#endif
if (mAlbumArt == NULL) {
LOGE("not enough memory for MediaAlbumArt size=%u", size);
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mAlbumArtDealer.clear();
+#endif
delete albumArt;
return NULL;
}
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 4aab94f..7e6d223 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -24,7 +24,6 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <binder/IMemory.h>
-
#include <media/MediaMetadataRetrieverInterface.h>
@@ -63,6 +62,10 @@ private:
int mMode;
// Keep the shared memory copy of album art and capture frame (for thumbnail)
+#ifdef USE_ECLAIR_MEMORYDEALER
+ sp<MemoryDealer> mAlbumArtDealer;
+ sp<MemoryDealer> mThumbnailDealer;
+#endif
sp<IMemory> mAlbumArt;
sp<IMemory> mThumbnail;
};
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 531fd11..573932f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -133,6 +133,10 @@ status_t StagefrightRecorder::setParameters(const String8 &params) {
return OK;
}
+status_t StagefrightRecorder::setCameraParameters(const String8 &params) {
+ return OK;
+}
+
status_t StagefrightRecorder::setListener(const sp<IMediaPlayerClient> &listener) {
mListener = listener;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 7ec412d..e5a84c1 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -43,6 +43,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setParameters(const String8& params);
+ virtual status_t setCameraParameters(const String8& params);
virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
virtual status_t prepare();
virtual status_t start();
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 81f995b..c4b88cc 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -47,10 +47,11 @@ LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT
endif
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
+ $(JNI_H_INCLUDE) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
$(TOP)/external/opencore/android \
- $(TOP)/external/tremolo
+ $(TOP)/external/tremolo \
+ $(TOP)/external/flac/include
LOCAL_SHARED_LIBRARIES := \
libbinder \
@@ -60,8 +61,13 @@ LOCAL_SHARED_LIBRARIES := \
libui \
libsonivox \
libvorbisidec \
- libsurfaceflinger_client \
- libcamera_client
+ libFLAC
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client \
+ libcamera_client
+endif
LOCAL_STATIC_LIBRARIES := \
libstagefright_aacdec \
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 69da7ef..e9a7248 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1211,8 +1211,11 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
}
size_t totalSize = def.nBufferCountActual * def.nBufferSize;
+#ifdef USE_ECLAIR_MEMORYDEALER
+ mDealer[portIndex] = new MemoryDealer(totalSize);
+#else
mDealer[portIndex] = new MemoryDealer(totalSize, "OMXCodec");
-
+#endif
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
CHECK(mem.get() != NULL);
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 03287dd1..25236cf 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -30,6 +30,9 @@
#include <Tremolo/ivorbiscodec.h>
#include <Tremolo/ivorbisfile.h>
+// FLAC includes
+#include <FLAC/all.h>
+
namespace android {
StagefrightMediaScanner::StagefrightMediaScanner()
@@ -42,7 +45,8 @@ static bool FileHasAcceptableExtension(const char *extension) {
static const char *kValidExtensions[] = {
".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
- ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota"
+ ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
+ ".flac"
};
static const size_t kNumValidExtensions =
sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
@@ -144,10 +148,78 @@ failure:
return UNKNOWN_ERROR;
}
+static FLAC__StreamDecoderWriteStatus flac_write(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) {
+ (void)decoder, (void)frame, (void)buffer, (void)client_data;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void flac_error(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) {
+ (void)decoder, (void)status, (void)client_data;
+}
+
+static void flac_metadata(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) {
+ MediaScannerClient *client = (MediaScannerClient *)client_data;
+
+ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ FLAC__uint64 duration = 1000 * metadata->data.stream_info.total_samples / metadata->data.stream_info.sample_rate;
+ if (duration > 0) {
+ char buffer[20];
+ sprintf(buffer, "%lld", duration);
+ if (!client->addStringTag("duration", buffer))
+ return;
+ }
+ } else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+ for (uint32_t i = 0; i < metadata->data.vorbis_comment.num_comments; i++) {
+ char *ptr = (char *)metadata->data.vorbis_comment.comments[i].entry;
+
+ char *val = strchr(ptr, '=');
+ if (val) {
+ int keylen = val++ - ptr;
+ char key[keylen + 1];
+ strncpy(key, ptr, keylen);
+ key[keylen] = 0;
+ LOGD("flac_metadata: key: %s value: %s", key, val);
+ if (!client->addStringTag(key, val)) return;
+ }
+ }
+ }
+}
+
+static status_t HandleFLAC(const char *filename, MediaScannerClient *client)
+{
+ status_t status = UNKNOWN_ERROR;
+
+ FLAC__StreamDecoder *decoder;
+
+ decoder = FLAC__stream_decoder_new();
+ if (!decoder)
+ return status;
+
+ FLAC__stream_decoder_set_md5_checking(decoder, false);
+ FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+ FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+ FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ FLAC__StreamDecoderInitStatus init_status;
+ init_status = FLAC__stream_decoder_init_file(decoder, filename, flac_write, flac_metadata, flac_error, client);
+ if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ goto exit;
+
+ if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+ goto exit;
+
+ status = OK;
+
+exit:
+ FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+
+ return OK;
+}
+
status_t StagefrightMediaScanner::processFile(
const char *path, const char *mimeType,
MediaScannerClient &client) {
- LOGV("processFile '%s'.", path);
client.setLocale(locale());
client.beginFile();
@@ -179,6 +251,10 @@ status_t StagefrightMediaScanner::processFile(
return HandleOGG(path, &client);
}
+ if (!strcasecmp(extension, ".flac")) {
+ return HandleFLAC(path, &client);
+ }
+
if (mRetriever->setDataSource(path) == OK
&& mRetriever->setMode(
METADATA_MODE_METADATA_RETRIEVAL_ONLY) == OK) {
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index b9ba1be..7e8a14a 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -13,9 +13,13 @@ LOCAL_SHARED_LIBRARIES := \
libmedia \
libutils \
libui \
- libcutils \
- libsurfaceflinger_client\
- libcamera_client
+ libcutils
+
+ifneq ($(BOARD_USES_ECLAIR_LIBCAMERA),true)
+ LOCAL_SHARED_LIBRARIES += \
+ libsurfaceflinger_client \
+ libcamera_client
+endif
LOCAL_MODULE:= libstagefright_color_conversion
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index fcf506d..0245c11 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -24,7 +24,11 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#ifdef USE_ECLAIR_MEMORYDEALER
#include <binder/MemoryDealer.h>
+#else
+#include <binder/MemoryDealer.h>
+#endif
#include <media/IMediaPlayerService.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
@@ -286,7 +290,11 @@ status_t Harness::testStateTransitions(
return OK;
}
+#ifdef USE_ECLAIR_MEMORYDEALER
+ sp<MemoryDealer> dealer = new MemoryDealer(8 * 1024 * 1024);
+#else
sp<MemoryDealer> dealer = new MemoryDealer(8 * 1024 * 1024, "OMXHarness");
+#endif
IOMX::node_id node;
status_t err =
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 89b3e1f..40317e7 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1043,6 +1043,10 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
+ if (share_list != EGL_NO_CONTEXT) {
+ egl_context_t* const c = get_context(share_list);
+ share_list = c->context;
+ }
EGLContext context = cnx->egl.eglCreateContext(
dp->disp[i].dpy, dp->disp[i].config[index],
share_list, attrib_list);
diff --git a/packages/VpnServices/src/com/android/server/vpn/OpenvpnService.java b/packages/VpnServices/src/com/android/server/vpn/OpenvpnService.java
new file mode 100644
index 0000000..6bb6496
--- /dev/null
+++ b/packages/VpnServices/src/com/android/server/vpn/OpenvpnService.java
@@ -0,0 +1,423 @@
+/*
+ * 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.server.vpn;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.net.vpn.OpenvpnProfile;
+import android.net.vpn.VpnManager;
+import android.security.Credentials;
+import android.util.Log;
+
+/**
+ * The service that manages the openvpn VPN connection.
+ */
+class OpenvpnService extends VpnService<OpenvpnProfile> {
+ private static final String OPENVPN_DAEMON = "openvpn";
+ private static final String MTPD = "mtpd";
+ private static final String USE_INLINE = "[[INLINE]]";
+ private static final String USE_KEYSTORE = "[[ANDROID]]";
+ private static final String TAG = OpenvpnService.class.getSimpleName();
+ private static int count = 0;
+
+ private final String socketName = OPENVPN_DAEMON + getCount();
+
+ private transient OpenvpnThread thread = null;
+
+ private transient String mPassword;
+ private transient String mUsername;
+
+ private synchronized static String getCount() {
+ return Integer.toString(count++);
+ }
+
+ @Override
+ protected void connect(String serverIp, String username, String password)
+ throws IOException {
+ OpenvpnProfile p = getProfile();
+ ArrayList<String> args = new ArrayList<String>();
+
+ mUsername = username;
+ mPassword = password;
+
+ args.add(OPENVPN_DAEMON);
+ args.add("--dev");
+ if (p.getDevice() != null) {
+ args.add(p.getDevice());
+ } else {
+ args.add("tun");
+ }
+ args.add("--remote");
+ args.add(serverIp);
+ args.add("--nobind");
+ args.add("--proto");
+ args.add(p.getProto());
+ args.add("--client");
+ args.add("--rport");
+ args.add(p.getPort());
+ if (p.getCAName() != null) {
+ args.add("--ca");
+ args.add(USE_INLINE);
+ args.add(USE_KEYSTORE + Credentials.CA_CERTIFICATE + p.getCAName());
+ }
+ if (p.getCertName() != null) {
+ args.add("--cert");
+ args.add(USE_INLINE);
+ args.add(USE_KEYSTORE + Credentials.USER_CERTIFICATE + p.getCertName());
+ args.add("--key");
+ args.add(USE_INLINE);
+ args.add(USE_KEYSTORE + Credentials.USER_PRIVATE_KEY + p.getCertName());
+ }
+ args.add("--persist-tun");
+ args.add("--persist-key");
+ args.add("--management");
+ args.add("/dev/socket/" + socketName);
+ args.add("unix");
+ args.add("--management-hold");
+ if (p.getUseCompLzo()) {
+ args.add("--comp-lzo");
+ }
+ if (p.getRedirectGateway()) {
+ args.add("--redirect-gateway def1");
+ }
+ if (p.getUserAuth()) {
+ args.add("--auth-user-pass");
+ args.add("--management-query-passwords");
+ }
+ if (p.getSupplyAddr()) {
+ args.add("--ifconfig");
+ args.add(p.getLocalAddr());
+ args.add(p.getRemoteAddr());
+ }
+ if (p.getCipher() != null) {
+ args.add("--cipher");
+ args.add(p.getCipher());
+ }
+ if (p.getKeySize() != null && !p.getKeySize().equals("")) {
+ args.add("--keysize");
+ args.add(p.getKeySize());
+ }
+ args.add("--up");
+ args.add("/system/xbin/openvpn-up.sh");
+ args.add("--script-security");
+ args.add("2");
+
+ if (p.getExtra() != null && !p.getExtra().equals("")) {
+ Scanner s = new Scanner(p.getExtra());
+ while(s.hasNext()) args.add(s.next());
+ }
+ DaemonProxy mtpd = getDaemons().startDaemon(MTPD);
+ mtpd.sendCommand(args.toArray(new String[args.size()]));
+ }
+
+ @Override
+ protected void disconnect() {
+ if (thread != null)
+ thread.disconnectAndWait();
+ }
+
+ @Override
+ void waitUntilConnectedOrTimedout() throws IOException {
+ thread = new OpenvpnThread();
+ thread.openvpnStart();
+ thread.waitConnect(60);
+ setVpnStateUp(true);
+ }
+
+ @Override
+ protected void recover() {
+ try {
+ thread = new OpenvpnThread();
+ thread.openvpnStart();
+ } catch (IOException e) {
+ onError(e);
+ }
+ }
+
+ void startConnectivityMonitor() {
+ /* Openvpn is completely event driven, so we don't need
+ * a polling monitor at all, so do nothing here */
+ }
+
+ private class OpenvpnThread extends Thread {
+ InputStream in;
+ OutputStream out;
+ LocalSocket mSocket;
+
+ boolean finalDisconnect = false;
+ boolean firstConnect = false;
+ boolean disconnecting = false;
+ boolean passwordError = false;
+
+ boolean SFbool;
+ volatile String SFreason;
+ String vpnState = "WAIT"; // initial state
+
+ OpenvpnThread() throws IOException {
+ openSocket();
+ in = mSocket.getInputStream();
+ out = mSocket.getOutputStream();
+ }
+
+ public void openvpnStart() throws IOException {
+ super.start();
+ send("state on"); // make state dynamic
+ send("log on"); // dynamically log over the socket
+ send("hold off"); // don't hold for subsequent reconnects
+ send("hold release"); // release from hold
+ send("bytecount 2"); // need this to update the monitor
+ }
+
+ public synchronized void disconnectAndWait() {
+ try {
+ disconnecting = true;
+ send("signal SIGTERM");
+ while (!finalDisconnect)
+ this.wait();
+ } catch(Exception e) {
+ // we're done
+ }
+ }
+
+ public synchronized void waitConnect(long seconds) throws IOException {
+ long endTime = System.currentTimeMillis() + seconds * 1000;
+ long wait;
+ while (!isConnected() && (wait = (endTime - System.currentTimeMillis())) > 0) {
+ try {
+ this.wait(wait);
+ } catch(InterruptedException e) {
+ // do nothing
+ }
+ if (passwordError)
+ throw new VpnConnectingError(VpnManager.VPN_ERROR_AUTH);
+ }
+ if (!isConnected())
+ throw new VpnConnectingError(VpnManager.VPN_ERROR_CONNECTION_FAILED);
+ firstConnect = true;
+ }
+
+ private boolean isConnected() {
+ return vpnState.equals("CONNECTED");
+ }
+
+ private void openSocket() throws IOException {
+ LocalSocket s = new LocalSocket();
+ LocalSocketAddress a = new LocalSocketAddress(socketName,
+ LocalSocketAddress.Namespace.RESERVED);
+ IOException excp = null;
+ for (int i = 0; i < 10; i++) {
+ try {
+ s.connect(a);
+ mSocket = s;
+ return;
+ } catch (IOException e) {
+ excp = e;
+ try {
+ Thread.currentThread().sleep(500);
+ } catch (InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ throw excp;
+ }
+
+ private synchronized boolean waitForSuccessOrFail() {
+ SFreason = null;
+ try {
+ while (SFreason == null) {
+ this.wait();
+ }
+ return SFbool;
+ } catch(InterruptedException e) {
+ return false;
+ }
+ }
+
+ private synchronized void signalSuccessOrFail(boolean success, String reason) {
+ SFbool = success;
+ SFreason = reason;
+ this.notifyAll();
+ }
+
+
+ private synchronized void sendAsync(String str) throws IOException {
+ str += "\n";
+ out.write(str.getBytes());
+ out.flush();
+ }
+
+ private boolean send(String str) throws IOException {
+ sendAsync(str);
+ return waitForSuccessOrFail();
+ }
+
+ private synchronized void signalState(String s) {
+ // state strings come as <date in secs>, <state>, <other stuff>
+ int first = s.indexOf(',');
+ if (first == -1)
+ return;
+ int second = s.indexOf(',', first + 1);
+ if (second == -1)
+ return;
+ String state = s.substring(first + 1, second);
+
+ /*
+ * state can be:
+ *
+ *
+ * CONNECTING -- OpenVPN's initial state.
+ * WAIT -- (Client only) Waiting for initial response
+ * from server.
+ * AUTH -- (Client only) Authenticating with server.
+ * GET_CONFIG -- (Client only) Downloading configuration options
+ * from server.
+ * ASSIGN_IP -- Assigning IP address to virtual network
+ * interface.
+ * ADD_ROUTES -- Adding routes to system.
+ * CONNECTED -- Initialization Sequence Completed.
+ * RECONNECTING -- A restart has occurred.
+ * EXITING -- A graceful exit is in progress.
+ *
+ * Really all we care about is connected or not
+ */
+ vpnState = state;
+ this.notifyAll();
+ if (state.equals("EXITING") && firstConnect && !disconnecting)
+ onError(new IOException("Connection Closed"));
+ }
+
+ private synchronized void signalPassword(String s) throws IOException {
+ /* message should be Need '<auth type>' password
+ * but coult be Verification Failed: '<auth type'
+ */
+
+ int first = s.indexOf('\'');
+ int second = s.indexOf('\'', first + 1);
+ final String authType = s.substring(first + 1, second);
+
+ /* AuthType can be one of
+ *
+ * "Auth" - regular client server authentication
+ * "Private Key" - password for private key (unimplemented)
+ */
+
+ if (s.startsWith("Need")) {
+ /* we're in the processor thread, so we have to send
+ * these asynchronously to avoid a deadlock */
+ sendAsync("username '" + authType +"' '" + mUsername + "'");
+ sendAsync("password '" + authType +"' '" + mPassword + "'");
+ } else {
+ // must be signalling authentication failure
+ passwordError = true;
+ this.notifyAll();
+ }
+ }
+
+ private void signalBytecount(String s) {
+ int index = s.indexOf(',');
+ if (index == -1)
+ // no , in message, ignore it
+ return;
+
+ String in = s.substring(0, index);
+ String out = s.substring(index+1);
+ vpnStateUpdate(Long.parseLong(in), Long.parseLong(out));
+ }
+
+ private void signalLog(String s) {
+ //log format is <date in secs>,<severity>,<message>
+ int first = s.indexOf(',');
+ if (first == -1)
+ return;
+ int second = s.indexOf(',', first + 1);
+ if (second == -1)
+ return;
+ String message = s.substring(second + 1);
+ Log.i("openvpn", message);
+ }
+
+ private void parseLine(String s) throws IOException {
+ int index = s.indexOf(':');
+ if (index == -1)
+ // no : in message, ignore it
+ return;
+
+ String token = s.substring(0, index);
+ String body = s.substring(index +1);
+
+ if (token.equals(">INFO")) {
+ // This is the starting string, just skip it
+ } else if (token.equals("SUCCESS")) {
+ signalSuccessOrFail(true, body);
+ } else if (token.equals("ERROR")) {
+ signalSuccessOrFail(false, body);
+ } else if (token.equals(">STATE")) {
+ signalState(body);
+ } else if (token.equals(">FATAL")) {
+ signalState("EXITING," + body);
+ } else if (token.equals(">PASSWORD")) {
+ signalPassword(body);
+ } else if (token.equals(">LOG")) {
+ signalLog(body);
+ }else if (token.equals(">HOLD")) {
+ // just warning us we're in a hold state, ignore
+ } else if (token.equals(">BYTECOUNT")) {
+ signalBytecount(body);
+ } else {
+ Log.w(TAG, "Unknown control token:\"" + token + "\"");
+ }
+ }
+
+ public void run() {
+
+ System.out.println("THREAD " + this + " RUNNING");
+
+ try {
+ int c;
+ StringBuffer s = new StringBuffer();
+ while (true) {
+ c = in.read();
+ if (c == -1)
+ throw new IOException("End of Stream");
+ if (c == '\n') {
+ parseLine(s.toString());
+ s = new StringBuffer();
+ continue;
+ }
+ if (c == '\r')
+ continue;
+ s.append((char)c);
+ }
+ } catch(IOException e) {
+ // terminate
+ } finally {
+ synchronized(this) {
+ finalDisconnect = true;
+ this.notifyAll();
+ }
+ System.out.println("THREAD " + this + " TERMINATED");
+ }
+ }
+ }
+}
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java b/packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java
index 499195f..2346299 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java
@@ -99,7 +99,7 @@ class VpnDaemons implements Serializable {
return 0;
}
- private synchronized DaemonProxy startDaemon(String daemonName)
+ synchronized DaemonProxy startDaemon(String daemonName)
throws IOException {
DaemonProxy daemon = new DaemonProxy(daemonName);
mDaemonList.add(daemon);
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index 63b87b1..7c64f95 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -85,6 +85,13 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
String password) throws IOException;
/**
+ * Disconnects the vpn
+ */
+ protected void disconnect() {
+ mDaemons.stopAll();
+ }
+
+ /**
* Returns the daemons management class for this service object.
*/
protected VpnDaemons getDaemons() {
@@ -110,14 +117,19 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
recover(context);
}
+ // intended for override by subclasses
+ protected void recover() {
+ startConnectivityMonitor();
+ }
+
void recover(VpnServiceBinder context) {
mContext = context;
mNotification = new NotificationHelper();
if (VpnState.CONNECTED.equals(mState)) {
Log.i("VpnService", " recovered: " + mProfile.getName());
- startConnectivityMonitor();
- }
+ recover();
+ }
}
VpnState getState() {
@@ -147,7 +159,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
setState(VpnState.DISCONNECTING);
mNotification.showDisconnect();
- mDaemons.stopAll();
+ disconnect();
} catch (Throwable e) {
Log.e(TAG, "onDisconnect()", e);
} finally {
@@ -155,7 +167,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
}
}
- private void onError(Throwable error) {
+ void onError(Throwable error) {
// error may occur during or after connection setup
// and it may be due to one or all services gone
if (mError != null) {
@@ -167,7 +179,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
onDisconnect();
}
- private void onError(int errorCode) {
+ void onError(int errorCode) {
onError(new VpnConnectingError(errorCode));
}
@@ -183,7 +195,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
}
}
- private void waitUntilConnectedOrTimedout() throws IOException {
+ void waitUntilConnectedOrTimedout() throws IOException {
sleep(2000); // 2 seconds
for (int i = 0; i < 80; i++) {
if (mState != VpnState.CONNECTING) {
@@ -207,6 +219,21 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
}
}
+ void setVpnStateUp(boolean state) throws IOException {
+ if (state) {
+ SystemProperties.set(VPN_STATUS, VPN_IS_UP);
+ onConnected();
+ mNotification.update(System.currentTimeMillis());
+ } else {
+ SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
+ }
+ }
+
+ void vpnStateUpdate(long in, long out) {
+ // currently don't show in and out bytes in status
+ mNotification.update(System.currentTimeMillis());
+ }
+
private synchronized void onConnected() throws IOException {
if (DBG) Log.d(TAG, "onConnected()");
@@ -276,6 +303,11 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
private void setVpnDns() {
String vpnDns1 = SystemProperties.get(VPN_DNS1);
String vpnDns2 = SystemProperties.get(VPN_DNS2);
+ if (vpnDns1.length() == 0) {
+ Log.i(TAG, "No vpn dns supplied, not updating");
+ return;
+ }
+
SystemProperties.set(DNS1, vpnDns1);
SystemProperties.set(DNS2, vpnDns2);
Log.i(TAG, String.format("set vpn dns prop: %s, %s",
@@ -323,7 +355,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
}
}
- private void startConnectivityMonitor() {
+ void startConnectivityMonitor() {
new Thread(new Runnable() {
public void run() {
Log.i(TAG, "VPN connectivity monitor running");
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 5672a01..162aea7 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -22,6 +22,7 @@ import android.net.vpn.IVpnService;
import android.net.vpn.L2tpIpsecProfile;
import android.net.vpn.L2tpIpsecPskProfile;
import android.net.vpn.L2tpProfile;
+import android.net.vpn.OpenvpnProfile;
import android.net.vpn.PptpProfile;
import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
@@ -47,7 +48,7 @@ public class VpnServiceBinder extends Service {
private static final String TAG = VpnServiceBinder.class.getSimpleName();
private static final boolean DBG = true;
- private static final String STATES_FILE_RELATIVE_PATH = "/misc/vpn/.states";
+ private static final String STATES_FILE_RELATIVE_PATH = "/data/misc/vpn/.states";
// The actual implementation is delegated to the VpnService class.
private VpnService<? extends VpnProfile> mService;
@@ -159,6 +160,11 @@ public class VpnServiceBinder extends Service {
l2tp.setContext(this, (L2tpProfile) p);
return l2tp;
+ case OPENVPN:
+ OpenvpnService ovpn = new OpenvpnService();
+ ovpn.setContext(this, (OpenvpnProfile)p );
+ return ovpn;
+
case PPTP:
PptpService pptp = new PptpService();
pptp.setContext(this, (PptpProfile) p);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 81b8d40..5c8ee53 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -430,6 +430,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public NetworkInfo getNetworkInfo(int networkType) {
enforceAccessPermission();
+
+ // HACK! - return a stub NetworkInfo object to make bad apps happy.
+ if (ConnectivityManager.TYPE_WIMAX == networkType) {
+ return NetworkInfo.getEmptyWimaxNetworkInfo();
+ }
+
if (ConnectivityManager.isNetworkTypeValid(networkType)) {
NetworkStateTracker t = mNetTrackers[networkType];
if (t != null)
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 414b69f..e198118 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -23,27 +23,32 @@ import android.view.Surface;
import android.view.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.io.FileInputStream;
+import java.util.StringTokenizer;
+import android.view.RawInputEvent;
public class InputDevice {
static final boolean DEBUG_POINTERS = false;
static final boolean DEBUG_HACKS = false;
-
+ static final boolean DEBUG_MOUSE = false;
+ static final String TAG = "InputDevice";
+
/** Amount that trackball needs to move in order to generate a key event. */
static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
/** Maximum number of pointers we will track and report. */
static final int MAX_POINTERS = 10;
-
+
/**
* Slop distance for jumpy pointer detection.
* The vertical range of the screen divided by this is our epsilon value.
*/
private static final int JUMPY_EPSILON_DIVISOR = 212;
-
+
/** Number of jumpy points to drop for touchscreens that need it. */
private static final int JUMPY_TRANSITION_DROPS = 3;
private static final int JUMPY_DROP_LIMIT = 3;
-
+
final int id;
final int classes;
final String name;
@@ -51,18 +56,18 @@ public class InputDevice {
final AbsoluteInfo absY;
final AbsoluteInfo absPressure;
final AbsoluteInfo absSize;
-
+
long mKeyDownTime = 0;
int mMetaKeysState = 0;
-
+
// For use by KeyInputQueue for keeping track of the current touch
// data in the old non-multi-touch protocol.
final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
-
+
final MotionState mAbs = new MotionState(0, 0);
final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
TRACKBALL_MOVEMENT_THRESHOLD);
-
+
static class MotionState {
int xPrecision;
int yPrecision;
@@ -72,16 +77,16 @@ public class InputDevice {
boolean changed = false;
boolean everChanged = false;
long mDownTime = 0;
-
+
// The currently assigned pointer IDs, corresponding to the last data.
int[] mPointerIds = new int[MAX_POINTERS];
-
+
// This is the last generated pointer data, ordered to match
// mPointerIds.
boolean mSkipLastPointers;
int mLastNumPointers = 0;
final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-
+
// This is the next set of pointer data being generated. It is not
// in any known order, and will be propagated in to mLastData
// as part of mapping it to the appropriate pointer IDs.
@@ -90,14 +95,14 @@ public class InputDevice {
int mNextNumPointers = 0;
final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
+ MotionEvent.NUM_SAMPLE_DATA];
-
+
// Used to determine whether we dropped bad data, to avoid doing
// it repeatedly.
final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
// Used to count the number of jumpy points dropped.
private int mJumpyPointsDropped = 0;
-
+
// Used to perform averaging of reported coordinates, to smooth
// the data and filter out transients during a release.
static final int HISTORY_SIZE = 5;
@@ -106,19 +111,19 @@ public class InputDevice {
final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
* HISTORY_SIZE];
final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-
+
// Temporary data structures for doing the pointer ID mapping.
final int[] mLast2Next = new int[MAX_POINTERS];
final int[] mNext2Last = new int[MAX_POINTERS];
final long[] mNext2LastDistance = new long[MAX_POINTERS];
-
+
// Temporary data structure for generating the final motion data.
final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-
+
// This is not used here, but can be used by callers for state tracking.
int mAddingPointerOffset = 0;
final boolean[] mDown = new boolean[MAX_POINTERS];
-
+
void dumpIntArray(PrintWriter pw, int[] array) {
pw.print("[");
for (int i=0; i<array.length; i++) {
@@ -127,7 +132,7 @@ public class InputDevice {
}
pw.print("]");
}
-
+
void dumpBooleanArray(PrintWriter pw, boolean[] array) {
pw.print("[");
for (int i=0; i<array.length; i++) {
@@ -136,7 +141,7 @@ public class InputDevice {
}
pw.print("]");
}
-
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision);
pw.print(" yPrecision="); pw.println(yPrecision);
@@ -168,7 +173,7 @@ public class InputDevice {
pw.print(prefix); pw.print("mDown=");
dumpBooleanArray(pw, mDown); pw.println("");
}
-
+
MotionState(int mx, int my) {
xPrecision = mx;
yPrecision = my;
@@ -178,7 +183,7 @@ public class InputDevice {
mPointerIds[i] = i;
}
}
-
+
/**
* Special hack for devices that have bad screen data: if one of the
* points has moved more than a screen height from the last position,
@@ -195,13 +200,13 @@ public class InputDevice {
if (mNextNumPointers != mLastNumPointers) {
return;
}
-
+
// We consider a single movement across more than a 7/16 of
// the long size of the screen to be bad. This was a magic value
// determined by looking at the maximum distance it is feasible
// to actually move in one sample.
final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
-
+
// Look through all new points and see if any are farther than
// acceptable from all previous points.
for (int i=mNextNumPointers-1; i>=0; i--) {
@@ -244,31 +249,31 @@ public class InputDevice {
mDroppedBadPoint[i] = dropped;
}
}
-
+
void dropJumpyPoint(InputDevice dev) {
// We should always have absY, but let's be paranoid.
if (dev.absY == null) {
return;
}
final int jumpyEpsilon = dev.absY.range / JUMPY_EPSILON_DIVISOR;
-
+
final int nextNumPointers = mNextNumPointers;
final int lastNumPointers = mLastNumPointers;
final int[] nextData = mNextData;
final int[] lastData = mLastData;
-
+
if (nextNumPointers != mLastNumPointers) {
if (DEBUG_HACKS) {
- Slog.d("InputDevice", "Different pointer count " + lastNumPointers +
+ Slog.d("InputDevice", "Different pointer count " + lastNumPointers +
" -> " + nextNumPointers);
for (int i = 0; i < nextNumPointers; i++) {
int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
- Slog.d("InputDevice", "Pointer " + i + " (" +
+ Slog.d("InputDevice", "Pointer " + i + " (" +
mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
}
}
-
+
// Just drop the first few events going from 1 to 2 pointers.
// They're bad often enough that they're not worth considering.
if (lastNumPointers == 1 && nextNumPointers == 2
@@ -278,36 +283,36 @@ public class InputDevice {
} else if (lastNumPointers == 2 && nextNumPointers == 1
&& mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
// The event when we go from 2 -> 1 tends to be messed up too
- System.arraycopy(lastData, 0, nextData, 0,
+ System.arraycopy(lastData, 0, nextData, 0,
lastNumPointers * MotionEvent.NUM_SAMPLE_DATA);
mNextNumPointers = lastNumPointers;
mJumpyPointsDropped++;
-
+
if (DEBUG_HACKS) {
for (int i = 0; i < mNextNumPointers; i++) {
int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
- Slog.d("InputDevice", "Pointer " + i + " replaced (" +
+ Slog.d("InputDevice", "Pointer " + i + " replaced (" +
mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
}
}
} else {
mJumpyPointsDropped = 0;
-
+
if (DEBUG_HACKS) {
Slog.d("InputDevice", "Transition - drop limit reset");
}
}
return;
}
-
+
// A 'jumpy' point is one where the coordinate value for one axis
// has jumped to the other pointer's location. No need to do anything
// else if we only have one pointer.
if (nextNumPointers < 2) {
return;
}
-
+
int badPointerIndex = -1;
int badPointerReplaceXWith = 0;
int badPointerReplaceYWith = 0;
@@ -315,13 +320,13 @@ public class InputDevice {
for (int i = nextNumPointers - 1; i >= 0; i--) {
boolean dropx = false;
boolean dropy = false;
-
+
// Limit how many times a jumpy point can get dropped.
if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) {
final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
final int x = nextData[ioff + MotionEvent.SAMPLE_X];
final int y = nextData[ioff + MotionEvent.SAMPLE_Y];
-
+
if (DEBUG_HACKS) {
Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")");
}
@@ -339,14 +344,14 @@ public class InputDevice {
dropx = Math.abs(x - xOther) <= jumpyEpsilon;
dropy = Math.abs(y - yOther) <= jumpyEpsilon;
}
-
+
if (dropx) {
int xreplace = lastData[MotionEvent.SAMPLE_X];
int yreplace = lastData[MotionEvent.SAMPLE_Y];
int distance = Math.abs(yreplace - y);
for (int j = 1; j < lastNumPointers; j++) {
final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
- int lasty = lastData[joff + MotionEvent.SAMPLE_Y];
+ int lasty = lastData[joff + MotionEvent.SAMPLE_Y];
int currDist = Math.abs(lasty - y);
if (currDist < distance) {
xreplace = lastData[joff + MotionEvent.SAMPLE_X];
@@ -354,7 +359,7 @@ public class InputDevice {
distance = currDist;
}
}
-
+
int badXDelta = Math.abs(xreplace - x);
if (badXDelta > badPointerDistance) {
badPointerDistance = badXDelta;
@@ -368,7 +373,7 @@ public class InputDevice {
int distance = Math.abs(xreplace - x);
for (int j = 1; j < lastNumPointers; j++) {
final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
- int lastx = lastData[joff + MotionEvent.SAMPLE_X];
+ int lastx = lastData[joff + MotionEvent.SAMPLE_X];
int currDist = Math.abs(lastx - x);
if (currDist < distance) {
xreplace = lastx;
@@ -376,7 +381,7 @@ public class InputDevice {
distance = currDist;
}
}
-
+
int badYDelta = Math.abs(yreplace - y);
if (badYDelta > badPointerDistance) {
badPointerDistance = badYDelta;
@@ -402,7 +407,7 @@ public class InputDevice {
mJumpyPointsDropped = 0;
}
}
-
+
/**
* Special hack for devices that have bad screen data: aggregate and
* compute averages of the coordinate data, to reduce the amount of
@@ -484,7 +489,7 @@ public class InputDevice {
}
}
}
-
+
// Now compute the average.
int start = mHistoryDataStart[i];
int end = mHistoryDataEnd[i];
@@ -519,7 +524,7 @@ public class InputDevice {
}
return mAveragedData;
}
-
+
private boolean assignPointer(int nextIndex, boolean allowOverlap) {
final int lastNumPointers = mLastNumPointers;
final int[] next2Last = mNext2Last;
@@ -528,12 +533,12 @@ public class InputDevice {
final int[] lastData = mLastData;
final int[] nextData = mNextData;
final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
-
+
if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex="
+ nextIndex + " dataOff=" + id);
final int x1 = nextData[id + MotionEvent.SAMPLE_X];
final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
-
+
long bestDistance = -1;
int bestIndex = -1;
for (int j=0; j<lastNumPointers; j++) {
@@ -552,51 +557,51 @@ public class InputDevice {
bestIndex = j;
}
}
-
+
if (DEBUG_POINTERS) Slog.v("InputDevice", "New index " + nextIndex
+ " best old index=" + bestIndex + " (distance="
+ bestDistance + ")");
next2Last[nextIndex] = bestIndex;
next2LastDistance[nextIndex] = bestDistance;
-
+
if (bestIndex < 0) {
return true;
}
-
+
if (last2Next[bestIndex] == -1) {
last2Next[bestIndex] = nextIndex;
return false;
}
-
+
if (DEBUG_POINTERS) Slog.v("InputDevice", "Old index " + bestIndex
+ " has multiple best new pointers!");
-
+
last2Next[bestIndex] = -2;
return true;
}
-
+
private int updatePointerIdentifiers() {
final int[] lastData = mLastData;
final int[] nextData = mNextData;
final int nextNumPointers = mNextNumPointers;
final int lastNumPointers = mLastNumPointers;
-
+
if (nextNumPointers == 1 && lastNumPointers == 1) {
System.arraycopy(nextData, 0, lastData, 0,
MotionEvent.NUM_SAMPLE_DATA);
return -1;
}
-
+
// Clear our old state.
final int[] last2Next = mLast2Next;
for (int i=0; i<lastNumPointers; i++) {
last2Next[i] = -1;
}
-
+
if (DEBUG_POINTERS) Slog.v("InputDevice",
"Update pointers: lastNumPointers=" + lastNumPointers
+ " nextNumPointers=" + nextNumPointers);
-
+
// Figure out the closes new points to the previous points.
final int[] next2Last = mNext2Last;
final long[] next2LastDistance = mNext2LastDistance;
@@ -604,25 +609,25 @@ public class InputDevice {
for (int i=0; i<nextNumPointers; i++) {
conflicts |= assignPointer(i, true);
}
-
+
// Resolve ambiguities in pointer mappings, when two or more
// new pointer locations find their best previous location is
// the same.
if (conflicts) {
if (DEBUG_POINTERS) Slog.v("InputDevice", "Resolving conflicts");
-
+
for (int i=0; i<lastNumPointers; i++) {
if (last2Next[i] != -2) {
continue;
}
-
+
// Note that this algorithm is far from perfect. Ideally
// we should do something like the one described at
// http://portal.acm.org/citation.cfm?id=997856
-
+
if (DEBUG_POINTERS) Slog.v("InputDevice",
"Resolving last index #" + i);
-
+
int numFound;
do {
numFound = 0;
@@ -638,7 +643,7 @@ public class InputDevice {
worstJ = j;
}
}
-
+
if (worstJ >= 0) {
if (DEBUG_POINTERS) Slog.v("InputDevice",
"Worst new pointer: " + worstJ
@@ -652,9 +657,9 @@ public class InputDevice {
} while (numFound > 2);
}
}
-
+
int retIndex = -1;
-
+
if (lastNumPointers < nextNumPointers) {
// We have one or more new pointers that are down. Create a
// new pointer identifier for one of them.
@@ -678,14 +683,14 @@ public class InputDevice {
i++;
nextId++;
}
-
+
if (DEBUG_POINTERS) Slog.v("InputDevice",
"New pointer id " + nextId + " at index " + i);
-
+
mLastNumPointers++;
retIndex = i;
mPointerIds[i] = nextId;
-
+
// And assign this identifier to the first new pointer.
for (int j=0; j<nextNumPointers; j++) {
if (next2Last[j] < 0) {
@@ -696,7 +701,7 @@ public class InputDevice {
}
}
}
-
+
// Propagate all of the current data into the appropriate
// location in the old data to match the pointer ID that was
// assigned to it.
@@ -711,7 +716,7 @@ public class InputDevice {
MotionEvent.NUM_SAMPLE_DATA);
}
}
-
+
if (lastNumPointers > nextNumPointers) {
// One or more pointers has gone up. Find the first one,
// and adjust accordingly.
@@ -725,10 +730,10 @@ public class InputDevice {
}
}
}
-
+
return retIndex;
}
-
+
void removeOldPointer(int index) {
final int lastNumPointers = mLastNumPointers;
if (index >= 0 && index < lastNumPointers) {
@@ -740,20 +745,20 @@ public class InputDevice {
mLastNumPointers--;
}
}
-
+
MotionEvent generateAbsMotion(InputDevice device, long curTime,
long curTimeNano, Display display, int orientation,
int metaState) {
-
+ boolean isMouse = (device.classes & RawInputEvent.CLASS_MOUSE) != 0;
if (mSkipLastPointers) {
mSkipLastPointers = false;
mLastNumPointers = 0;
}
-
- if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
+
+ if (!isMouse && (mNextNumPointers <= 0 && mLastNumPointers <= 0)) {
return null;
}
-
+
final int lastNumPointers = mLastNumPointers;
final int nextNumPointers = mNextNumPointers;
if (mNextNumPointers > MAX_POINTERS) {
@@ -761,24 +766,28 @@ public class InputDevice {
+ " exceeded maximum of " + MAX_POINTERS);
mNextNumPointers = MAX_POINTERS;
}
-
- int upOrDownPointer = updatePointerIdentifiers();
-
+
+ /*
+ * This is not used for mouse
+ */
+ int upOrDownPointer = isMouse ? 0 : updatePointerIdentifiers();
+
final float[] reportData = mReportData;
final int[] rawData;
- if (KeyInputQueue.BAD_TOUCH_HACK) {
+ if (!isMouse && KeyInputQueue.BAD_TOUCH_HACK) {
rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
nextNumPointers);
} else {
- rawData = mLastData;
+ rawData = isMouse ? mNextData : mLastData;
}
-
- final int numPointers = mLastNumPointers;
-
- if (DEBUG_POINTERS) Slog.v("InputDevice", "Processing "
+
+ final int numPointers = isMouse ? 1 : mLastNumPointers;
+
+ if (DEBUG_POINTERS || DEBUG_MOUSE)
+ Slog.v("InputDevice", "Processing "
+ numPointers + " pointers (going from " + lastNumPointers
- + " to " + nextNumPointers + ")");
-
+ + " to " + nextNumPointers + ")" + " touch hack "
+ + KeyInputQueue.BAD_TOUCH_HACK);
for (int i=0; i<numPointers; i++) {
final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
@@ -786,31 +795,50 @@ public class InputDevice {
reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
}
-
+
int action;
int edgeFlags = 0;
- if (nextNumPointers != lastNumPointers) {
- if (nextNumPointers > lastNumPointers) {
- if (lastNumPointers == 0) {
- action = MotionEvent.ACTION_DOWN;
- mDownTime = curTime;
+ if (!isMouse) {
+ if (nextNumPointers != lastNumPointers) {
+ if (nextNumPointers > lastNumPointers) {
+ if (lastNumPointers == 0) {
+ action = MotionEvent.ACTION_DOWN;
+ mDownTime = curTime;
+ } else {
+ action = MotionEvent.ACTION_POINTER_DOWN
+ | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+ }
} else {
- action = MotionEvent.ACTION_POINTER_DOWN
+ if (numPointers == 1) {
+ action = MotionEvent.ACTION_UP;
+ } else {
+ action = MotionEvent.ACTION_POINTER_UP
| (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ }
}
+ currentMove = null;
} else {
- if (numPointers == 1) {
+ action = MotionEvent.ACTION_MOVE;
+ }
+ } else {
+ if (mNextNumPointers != mLastNumPointers) {
+ if (mNextNumPointers == 1) {
+ action = MotionEvent.ACTION_DOWN;
+ mDownTime = curTime;
+ } else if (mNextNumPointers == 2) {
action = MotionEvent.ACTION_UP;
} else {
- action = MotionEvent.ACTION_POINTER_UP
- | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ action = MotionEvent.ACTION_MOVE;
}
+ mLastNumPointers = mNextNumPointers;
+ currentMove = null;
+ } else {
+ action = MotionEvent.ACTION_MOVE;
}
- currentMove = null;
- } else {
- action = MotionEvent.ACTION_MOVE;
+ if (DEBUG_MOUSE)
+ Slog.i(TAG, "mouse action " + action);
}
-
+
final int dispW = display.getWidth()-1;
final int dispH = display.getHeight()-1;
int w = dispW;
@@ -821,14 +849,14 @@ public class InputDevice {
w = h;
h = tmp;
}
-
+
final AbsoluteInfo absX = device.absX;
final AbsoluteInfo absY = device.absY;
final AbsoluteInfo absPressure = device.absPressure;
final AbsoluteInfo absSize = device.absSize;
for (int i=0; i<numPointers; i++) {
final int j = i * MotionEvent.NUM_SAMPLE_DATA;
-
+
if (absX != null) {
reportData[j + MotionEvent.SAMPLE_X] =
((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
@@ -840,16 +868,16 @@ public class InputDevice {
/ absY.range) * h;
}
if (absPressure != null) {
- reportData[j + MotionEvent.SAMPLE_PRESSURE] =
+ reportData[j + MotionEvent.SAMPLE_PRESSURE] =
((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
/ (float)absPressure.range);
}
if (absSize != null) {
- reportData[j + MotionEvent.SAMPLE_SIZE] =
+ reportData[j + MotionEvent.SAMPLE_SIZE] =
((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
/ (float)absSize.range);
}
-
+
switch (orientation) {
case Surface.ROTATION_90: {
final float temp = reportData[j + MotionEvent.SAMPLE_X];
@@ -870,7 +898,7 @@ public class InputDevice {
}
}
}
-
+
// We only consider the first pointer when computing the edge
// flags, since they are global to the event.
if (action == MotionEvent.ACTION_DOWN) {
@@ -885,9 +913,9 @@ public class InputDevice {
edgeFlags |= MotionEvent.EDGE_BOTTOM;
}
}
-
+
if (currentMove != null) {
- if (false) Slog.i("InputDevice", "Adding batch x="
+ if (DEBUG_MOUSE) Slog.i("InputDevice", "Adding batch x="
+ reportData[MotionEvent.SAMPLE_X]
+ " y=" + reportData[MotionEvent.SAMPLE_Y]
+ " to " + currentMove);
@@ -897,42 +925,42 @@ public class InputDevice {
}
return null;
}
-
+
MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
curTimeNano, action, numPointers, mPointerIds, reportData,
metaState, xPrecision, yPrecision, device.id, edgeFlags);
if (action == MotionEvent.ACTION_MOVE) {
currentMove = me;
}
-
- if (nextNumPointers < lastNumPointers) {
+
+ if ((!isMouse) && (nextNumPointers < lastNumPointers)) {
removeOldPointer(upOrDownPointer);
}
-
+
return me;
}
-
+
boolean hasMore() {
return mLastNumPointers != mNextNumPointers;
}
-
+
void finish() {
mNextNumPointers = mAddingPointerOffset = 0;
mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
}
-
+
MotionEvent generateRelMotion(InputDevice device, long curTime,
long curTimeNano, int orientation, int metaState) {
-
+
final float[] scaled = mReportData;
-
+
// For now we only support 1 pointer with relative motions.
scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
scaled[MotionEvent.SAMPLE_SIZE] = 0;
int edgeFlags = 0;
-
+
int action;
if (mNextNumPointers != mLastNumPointers) {
mNextData[MotionEvent.SAMPLE_X] =
@@ -950,7 +978,7 @@ public class InputDevice {
} else {
action = MotionEvent.ACTION_MOVE;
}
-
+
scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
switch (orientation) {
@@ -972,7 +1000,7 @@ public class InputDevice {
break;
}
}
-
+
if (currentMove != null) {
if (false) Slog.i("InputDevice", "Adding batch x="
+ scaled[MotionEvent.SAMPLE_X]
@@ -984,7 +1012,7 @@ public class InputDevice {
}
return null;
}
-
+
MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
curTimeNano, action, 1, mPointerIds, scaled, metaState,
xPrecision, yPrecision, device.id, edgeFlags);
@@ -994,14 +1022,14 @@ public class InputDevice {
return me;
}
}
-
+
static class AbsoluteInfo {
int minValue;
int maxValue;
int range;
int flat;
int fuzz;
-
+
final void dump(PrintWriter pw) {
pw.print("minValue="); pw.print(minValue);
pw.print(" maxValue="); pw.print(maxValue);
@@ -1010,7 +1038,7 @@ public class InputDevice {
pw.print(" fuzz="); pw.print(fuzz);
}
};
-
+
InputDevice(int _id, int _classes, String _name,
AbsoluteInfo _absX, AbsoluteInfo _absY,
AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index f30346b..5d0d127 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -50,10 +50,13 @@ import java.util.ArrayList;
public abstract class KeyInputQueue {
static final String TAG = "KeyInputQueue";
+ static final int UPKEY_KEYWORD = 19;
+ static final int DOWNKEY_KEYWORD = 20;
static final boolean DEBUG = false;
static final boolean DEBUG_VIRTUAL_KEYS = false;
static final boolean DEBUG_POINTERS = false;
+ static final boolean DEBUG_MOUSE = false;
/**
* Turn on some hacks we have to improve the touch interaction with a
@@ -85,6 +88,8 @@ public abstract class KeyInputQueue {
Display mDisplay = null;
int mDisplayWidth;
int mDisplayHeight;
+ int mCx;
+ int mCy;
int mOrientation = Surface.ROTATION_0;
int[] mKeyRotationMap = null;
@@ -322,6 +327,8 @@ public abstract class KeyInputQueue {
// buttons based on that display.
mDisplayWidth = display.getWidth();
mDisplayHeight = display.getHeight();
+ mCx = mDisplayWidth / 2;
+ mCy = mDisplayHeight / 2;
}
public void getInputConfiguration(Configuration config) {
@@ -639,11 +646,35 @@ public abstract class KeyInputQueue {
di.mAbs.mDown[0] = ev.value != 0;
// Trackball (mouse) protocol: press down or up.
- } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
- (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
- di.mRel.changed = true;
- di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
- send = true;
+ } else if (ev.scancode == RawInputEvent.BTN_MOUSE) {
+ if ((classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
+ di.mRel.changed = true;
+ di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
+ send = true;
+ } else if ((classes&RawInputEvent.CLASS_MOUSE) != 0) {
+ if (DEBUG_MOUSE)
+ Slog.i(TAG, "Mouse key event found, down:"
+ + ev.value + " was :" +
+ di.mAbs.mDown[0] + " Send " + send);
+ di.mAbs.changed = true;
+ di.mAbs.mNextNumPointers = (ev.value != 0) ? 1 : 2;
+ send = true;
+ }
+ } else if ((ev.scancode == RawInputEvent.BTN_RIGHT ||
+ ev.scancode == RawInputEvent.BTN_MIDDLE) &&
+ (classes&RawInputEvent.CLASS_MOUSE) != 0) {
+ boolean down = (ev.value != 0);
+ if (down)
+ di.mKeyDownTime = curTime;
+
+ addLocked(di, curTime, ev.flags,
+ RawInputEvent.CLASS_KEYBOARD,
+ newKeyEvent(di, di.mKeyDownTime, curTime, down,
+ (ev.scancode == RawInputEvent.BTN_RIGHT)
+ ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_MENU,
+ 0, scancode,
+ ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
+ ? KeyEvent.FLAG_WOKE_HERE : 0));
}
// Process position events from multitouch protocol.
@@ -695,15 +726,59 @@ public abstract class KeyInputQueue {
}
// Process movement events from trackball (mouse) protocol.
- } else if (ev.type == RawInputEvent.EV_REL &&
- (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
- // Add this relative movement into our totals.
- if (ev.scancode == RawInputEvent.REL_X) {
- di.mRel.changed = true;
- di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
- } else if (ev.scancode == RawInputEvent.REL_Y) {
- di.mRel.changed = true;
- di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
+ } else if (ev.type == RawInputEvent.EV_REL) {
+ if (DEBUG_MOUSE)
+ Slog.i(TAG, "rel event found, class :" + classes + " mouse value: " + RawInputEvent.CLASS_MOUSE);
+ if ((classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
+ // Add this relative movement into our totals.
+ if (ev.scancode == RawInputEvent.REL_X) {
+ di.mRel.changed = true;
+ di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
+ } else if (ev.scancode == RawInputEvent.REL_Y) {
+ di.mRel.changed = true;
+ di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
+ }
+ } else if ((classes&RawInputEvent.CLASS_MOUSE) != 0) {
+ if (ev.scancode == RawInputEvent.REL_X) {
+ di.mAbs.changed = true;
+ mCx += (int)ev.value;
+ mCx = ((mCx < 0) ? 0 : (mCx >= mDisplayWidth ? mDisplayWidth - 1 : mCx));
+ di.mAbs.mNextData[MotionEvent.SAMPLE_X] = mCx;
+ } else if (ev.scancode == RawInputEvent.REL_Y) {
+ di.mAbs.changed = true;
+ mCy += (int)ev.value;
+ mCy = ((mCy < 0) ? 0 : (mCy >= mDisplayHeight ? mDisplayHeight - 1 : mCy));
+ di.mAbs.mNextData[MotionEvent.SAMPLE_Y] = mCy;
+ } else if (ev.scancode == RawInputEvent.REL_WHEEL &&
+ (classes&RawInputEvent.CLASS_MOUSE) != 0) {
+ boolean down;
+ int keycode;
+ if (ev.value != 0) {
+ down = true;
+ di.mKeyDownTime = curTime;
+ } else {
+ down = false;
+ }
+ if (ev.value < 0){
+ keycode = rotateKeyCodeLocked(DOWNKEY_KEYWORD);
+ } else if(ev.value > 0){
+ keycode = rotateKeyCodeLocked(UPKEY_KEYWORD);
+ } else {
+ keycode = rotateKeyCodeLocked(ev.keycode);
+ }
+ addLocked(di, curTime, ev.flags,
+ RawInputEvent.CLASS_KEYBOARD,
+ newKeyEvent(di, di.mKeyDownTime, curTime, down,
+ keycode, 0, scancode,
+ ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
+ ? KeyEvent.FLAG_WOKE_HERE : 0));
+ addLocked(di, curTime, ev.flags,
+ RawInputEvent.CLASS_KEYBOARD,
+ newKeyEvent(di, di.mKeyDownTime, curTime, !down,
+ keycode, 0, scancode,
+ ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
+ ? KeyEvent.FLAG_WOKE_HERE : 0));
+ }
}
}
@@ -790,7 +865,8 @@ public abstract class KeyInputQueue {
me = ms.generateAbsMotion(di, curTime,
curTimeNano, mDisplay,
mOrientation, mGlobalMetaState);
- if (DEBUG_POINTERS) Slog.v(TAG, "Absolute: x="
+ if (DEBUG_POINTERS || DEBUG_MOUSE)
+ Slog.v(TAG, "Absolute: x="
+ di.mAbs.mNextData[MotionEvent.SAMPLE_X]
+ " y="
+ di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
@@ -799,8 +875,15 @@ public abstract class KeyInputQueue {
if (WindowManagerPolicy.WATCH_POINTER) {
Slog.i(TAG, "Enqueueing: " + me);
}
- addLocked(di, curTimeNano, ev.flags,
- RawInputEvent.CLASS_TOUCHSCREEN, me);
+ if ((classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ addLocked(di, curTime, ev.flags,
+ RawInputEvent.CLASS_TOUCHSCREEN, me);
+ } else if ((classes & RawInputEvent.CLASS_MOUSE) != 0) {
+ addLocked(di, curTime, ev.flags,
+ RawInputEvent.CLASS_MOUSE, me);
+ } else {
+ Slog.w(TAG, "Unknown classes? " + classes);
+ }
}
} while (ms.hasMore());
} else {
diff --git a/services/java/com/android/server/LightsService.java b/services/java/com/android/server/LightsService.java
index 9b57735..4fd2eb3 100644
--- a/services/java/com/android/server/LightsService.java
+++ b/services/java/com/android/server/LightsService.java
@@ -23,6 +23,7 @@ import android.os.IHardwareService;
import android.os.ServiceManager;
import android.os.Message;
import android.util.Slog;
+import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
@@ -94,13 +95,20 @@ public class LightsService {
public void pulse(int color, int onMS) {
synchronized (this) {
- if (mColor == 0 && !mFlashing) {
+ if (mColor == 0 && !mFlashing) {
setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
}
}
}
+ public void notificationPulse(int color, int onMs, int offMs) {
+ synchronized (this) {
+ setLightLocked(color, LIGHT_FLASH_TIMED, onMs, 1000, BRIGHTNESS_MODE_USER);
+ mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMs);
+ }
+ }
+
public void turnOff() {
synchronized (this) {
setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
@@ -114,13 +122,13 @@ public class LightsService {
}
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
- if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
- mColor = color;
- mMode = mode;
- mOnMS = onMS;
- mOffMS = offMS;
- setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
- }
+ if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
+ mColor = color;
+ mMode = mode;
+ mOnMS = onMS;
+ mOffMS = offMS;
+ setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ }
}
private int mId;
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 73d17ea..675c4b1 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -19,7 +19,6 @@ package com.android.server;
import com.android.server.status.IconData;
import com.android.server.status.NotificationData;
import com.android.server.status.StatusBarService;
-
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.INotificationManager;
@@ -43,6 +42,7 @@ import android.media.AudioManager;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Binder;
+import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -57,14 +57,27 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
import android.util.Log;
+import java.util.Timer;
+import java.util.TimerTask;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import android.os.PowerManager;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Random;
+
+//For Notification Colors.
+import android.graphics.Color;
class NotificationManagerService extends INotificationManager.Stub
{
@@ -106,6 +119,7 @@ class NotificationManagerService extends INotificationManager.Stub
// for enabling and disabling notification pulse behavior
private boolean mScreenOn = true;
+ private boolean mScreenUpdate = false;
private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
@@ -125,6 +139,7 @@ class NotificationManagerService extends INotificationManager.Stub
private boolean mBatteryCharging;
private boolean mBatteryLow;
private boolean mBatteryFull;
+ private int mBatteryLevel;
private NotificationRecord mLedNotification;
private static final int BATTERY_LOW_ARGB = 0xFFFF0000; // Charging Low - red solid on
@@ -133,6 +148,14 @@ class NotificationManagerService extends INotificationManager.Stub
private static final int BATTERY_BLINK_ON = 125;
private static final int BATTERY_BLINK_OFF = 2875;
+ private static ExecutorService threadExecutor;
+ private static int mLastLight = 0;
+ private static boolean isTimer = false;
+ private static boolean hasLights = false;
+ private static PowerManager PowerMan;
+ private static PowerManager.WakeLock powerWake = null;
+ //private static ExecutorService threadExecutor;
+
private static String idDebugString(Context baseContext, String packageName, int id) {
Context c = null;
@@ -317,7 +340,9 @@ class NotificationManagerService extends INotificationManager.Stub
boolean batteryLow = (level >= 0 && level <= Power.LOW_BATTERY_THRESHOLD);
int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
boolean batteryFull = (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90);
+ int percentage = intent.getIntExtra("scale", 100);
+ mBatteryLevel = level*100/percentage;
if (batteryCharging != mBatteryCharging ||
batteryLow != mBatteryLow ||
batteryFull != mBatteryFull) {
@@ -359,10 +384,18 @@ class NotificationManagerService extends INotificationManager.Stub
}
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
mScreenOn = true;
- updateNotificationPulse();
+ mScreenUpdate = true;
+ int mPulseScreen = Settings.System.getInt(mContext.getContentResolver(), Settings.System.TRACKBALL_SCREEN_ON, 0);
+ if(mPulseScreen == 0) { //Why bother if we are going to pulse anyways?
+ updateNotificationPulse();
+ }
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
- updateNotificationPulse();
+ mScreenUpdate = true;
+ int mPulseScreen = Settings.System.getInt(mContext.getContentResolver(), Settings.System.TRACKBALL_SCREEN_ON, 0);
+ if(mPulseScreen == 0) { //Why bother if we are going to pulse anyways?
+ updateNotificationPulse();
+ }
} else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK));
updateNotificationPulse();
@@ -824,6 +857,7 @@ class NotificationManagerService extends INotificationManager.Stub
if (mLedNotification == old) {
mLedNotification = null;
}
+ //updatePackageList(pkg);
//Slog.i(TAG, "notification.lights="
// + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
@@ -909,7 +943,7 @@ class NotificationManagerService extends INotificationManager.Stub
*/
private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
int mustNotHaveFlags) {
- EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
+ EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
synchronized (mNotificationList) {
int index = indexOfNotificationLocked(pkg, tag, id);
@@ -1037,9 +1071,78 @@ class NotificationManagerService extends INotificationManager.Stub
}
}
+ public boolean isNull(String mString) {
+ if(mString == null || mString.matches("null")
+ || mString.length() == 0
+ || mString.matches("|")
+ || mString.matches("")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //Grab our Array Information For Lights
+ public String[] getArray(String mGetFrom) {
+ if(isNull(mGetFrom)) {
+ return null;
+ }
+ String[] temp = mGetFrom.split("\\|");
+ return temp;
+ }
+
+ public String[] getPackageInfo(String mString) {
+ if(mString == null || mString == "=" || mString.length() == 0) {
+ return null;
+ }
+ String[] temp;
+ temp = mString.split("=");
+ return temp;
+ }
+
+ public class StartTimerClass implements Runnable {
+ private long sleepTimer;
+
+ public StartTimerClass(long timer) {
+ sleepTimer = timer;
+ }
+ public void run() {
+ powerWake.acquire(sleepTimer);
+ try {
+ Thread.sleep(sleepTimer);
+ } catch (InterruptedException e) {
+ }
+ isTimer = false;
+ updateLights();
+ //threadExecutor = null;
+ }
+ }
+
+ private int lastColor = 1;
+ private String[] colorList = {"green", "white", "red", "blue", "yellow", "cyan", "#800080", "#ffc0cb", "#ffa500", "#add8e6"};
+
+ public void newExecutor() {
+ threadExecutor = Executors.newSingleThreadExecutor();
+ }
+
// lock on mNotificationList
private void updateLightsLocked()
{
+ String[] mPackages;
+ String mPackageList = Settings.System.getString(mContext.getContentResolver(), Settings.System.NOTIFICATION_PACKAGE_COLORS);
+ mPackages = getArray(mPackageList);
+ int mPulseScreen = Settings.System.getInt(mContext.getContentResolver(), Settings.System.TRACKBALL_SCREEN_ON, 0);
+ int mSuccession = Settings.System.getInt(mContext.getContentResolver(), Settings.System.TRACKBALL_NOTIFICATION_SUCCESSION, 0);
+ int mRandomColor = Settings.System.getInt(mContext.getContentResolver(), Settings.System.TRACKBALL_NOTIFICATION_RANDOM, 0);
+ int mPulseAllColor = Settings.System.getInt(mContext.getContentResolver(), Settings.System.TRACKBALL_NOTIFICATION_PULSE_ORDER, 0);
+ int mBlendColor = Settings.System.getInt(mContext.getContentResolver(), Settings.System.TRACKBALL_NOTIFICATION_BLEND_COLOR, 0);
+
+ if(mBatteryLevel <= 15 || (mBlendColor == 1)) {
+ mSuccession = 0;
+ mRandomColor = 0;
+ mPulseAllColor = 0;
+ }
+
// Battery low always shows, other states only show if charging.
if (mBatteryLow) {
if (mBatteryCharging) {
@@ -1066,29 +1169,147 @@ class NotificationManagerService extends INotificationManager.Stub
if (n > 0) {
mLedNotification = mLights.get(n-1);
}
- }
+ } else if (mSuccession != 1) {
+ //We always want to have the newst notification to pulse without Succession
+ int n = mLights.size();
+ if (n > 0) {
+ mLedNotification = mLights.get(n-1);
+ }
+ }
// we only flash if screen is off and persistent pulsing is enabled
// and we are not currently in a call
- if (mLedNotification == null || mScreenOn || mInCall) {
- mNotificationLight.turnOff();
+ if (mLedNotification == null || (mScreenOn && (mPulseScreen == 0)) || mInCall) {
+ mNotificationLight.turnOff();
+ hasLights = false;
+ isTimer = false;
} else {
- int ledARGB = mLedNotification.notification.ledARGB;
- int ledOnMS = mLedNotification.notification.ledOnMS;
- int ledOffMS = mLedNotification.notification.ledOffMS;
- if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
- ledARGB = mDefaultNotificationColor;
- ledOnMS = mDefaultNotificationLedOn;
- ledOffMS = mDefaultNotificationLedOff;
- }
- if (mNotificationPulseEnabled) {
- // pulse repeatedly
- mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
- ledOnMS, ledOffMS);
- } else {
+ hasLights = true;
+ if(mSuccession == 1) {
+ int n = mLights.size();
+ if (n > 0) {
+ int thisLight = n;
+ if(mLastLight > thisLight) {
+ thisLight = 1;
+ } else {
+ thisLight = mLastLight + 1;
+ }
+ //One last arthmetic check for sanitys sake.
+ if((thisLight == (mLastLight - 1)) || (thisLight > n)) {
+ thisLight = 1;
+ }
+ mLedNotification = mLights.get(thisLight-1);
+ mLastLight = thisLight;
+ }
+ }
+ int ledARGB = mLedNotification.notification.ledARGB;
+ int ledOnMS = mLedNotification.notification.ledOnMS;
+ int ledOffMS = mLedNotification.notification.ledOffMS;
+ if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
+ ledARGB = mDefaultNotificationColor;
+ ledOnMS = mDefaultNotificationLedOn;
+ ledOffMS = mDefaultNotificationLedOff;
+ }
+ //Possible Cleaner way?
+ //String[] mPackageInfo = findPackage(mLedNotification.pkg);
+ //if(mPackageInfo != null) {
+ // ledARGB = Color.parseColor(mPackageInfo[1]);
+ // ledOffMS = Integer.parseInt(mPackageInfo[2]);
+ //}
+ if(mPackages != null) {
+ int i = 0;
+ for(i = 0; i < mPackages.length; i++) {
+ String[] mPackageInfo = getPackageInfo(mPackages[i]);
+ if(mPackageInfo == null) {
+ continue;
+ }
+ if(mPackageInfo[0].matches(mLedNotification.pkg)) {
+ if(mPackageInfo[1].equals("random")) {
+ Random generator = new Random();
+ int x = generator.nextInt(colorList.length - 1);
+ ledARGB = Color.parseColor(colorList[x]);
+ } else {
+ ledARGB = Color.parseColor(mPackageInfo[1]);
+ }
+ if(mPackageInfo[2].equals(".5")) {
+ ledOffMS = 500;
+ } else {
+ ledOffMS = (Integer.parseInt(mPackageInfo[2]) * 1000);
+ }
+ }
+ }
+ }
+
+ if(mRandomColor == 1) {
+ //Lets make this intresting...
+ Random generator = new Random();
+ int x = generator.nextInt(colorList.length - 1);
+ ledARGB = Color.parseColor(colorList[x]);
+ } else if(mPulseAllColor == 1) {
+ if(lastColor >= colorList.length)
+ lastColor = 1;
+
+ ledARGB = Color.parseColor(colorList[lastColor - 1]);
+ lastColor = lastColor + 1;
+ } else if(mBlendColor == 1) { // Blend lights: Credit to eshabtai for the application of this.
+ for (int n=0; n < mLights.size(); n++) {
+ int x = 0;
+ boolean found = false;
+ long pkgcolor = Color.parseColor("white");
+ for(x = 0; x < mPackages.length; x++) {
+ String[] mPackageInfo = getPackageInfo(mPackages[x]);
+ if(mPackageInfo == null) {
+ continue;
+ }
+ if(mPackageInfo[0].matches(mLights.get(n).pkg)) {
+ if(mPackageInfo[1].equals("random")) {
+ Random generator = new Random();
+ int j = generator.nextInt(colorList.length - 1);
+ pkgcolor = Color.parseColor(colorList[j]);
+ } else {
+ pkgcolor = Color.parseColor(mPackageInfo[1]);
+ }
+ found = true;
+ break;
+ }
+ }
+ if(found) {
+ ledARGB |= pkgcolor;
+ } else {
+ ledARGB |= mLights.get(n).notification.ledARGB;
+ }
+ }
+ }
+ if (mNotificationPulseEnabled) {
+ // pulse repeatedly
+ if((mSuccession == 1) || (mRandomColor == 1) || (mPulseAllColor == 1)) {
+ /* Our wake lock information to keep us alive */
+ if(powerWake == null) {
+ PowerMan = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ powerWake = PowerMan.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NotificationLights");
+ }
+ long scheduleTime = ledOnMS+ledOffMS;
+ if(scheduleTime < 2500) {
+ scheduleTime = 2500;
+ }
+ StartTimerClass timerRun = new StartTimerClass(scheduleTime);
+ if(threadExecutor == null) {
+ newExecutor();
+ }
+ if(isTimer == false) {
+ isTimer = true;
+ threadExecutor.execute(timerRun);
+ }
+ mNotificationLight.notificationPulse(ledARGB, ledOnMS, ledOffMS);
+ } else {
+ //We are going to divide the time in half, as it seems long when normal.
+ mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
+ ledOnMS, ledOffMS);
+ }
+ } else {
// pulse only once
- mNotificationLight.pulse(ledARGB, ledOnMS);
- }
+ mNotificationLight.pulse(ledARGB, ledOnMS);
+ }
}
}
@@ -1120,7 +1341,9 @@ class NotificationManagerService extends INotificationManager.Stub
// to accidentally lose.
private void updateAdbNotification() {
if (mAdbEnabled && mUsbConnected) {
- if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
+ if ("0".equals(SystemProperties.get("persist.adb.notify")) ||
+ Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ADB_NOTIFY, 1) == 0) {
return;
}
if (!mAdbNotificationShown) {
@@ -1137,7 +1360,6 @@ class NotificationManagerService extends INotificationManager.Stub
mAdbNotification = new Notification();
mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
mAdbNotification.when = 0;
- mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
mAdbNotification.tickerText = title;
mAdbNotification.defaults = 0; // please be quiet
mAdbNotification.sound = null;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 0b84c8d..136a042 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -962,13 +962,13 @@ class PackageManagerService extends IPackageManager.Stub {
SystemClock.uptimeMillis());
mAppInstallObserver = new AppDirObserver(
mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
- mAppInstallObserver.startWatching();
scanDirLI(mAppInstallDir, 0, scanMode);
+ mAppInstallObserver.startWatching();
mDrmAppInstallObserver = new AppDirObserver(
mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
- mDrmAppInstallObserver.startWatching();
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode);
+ mDrmAppInstallObserver.startWatching();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 7bbc32f..e0d1c49 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -75,6 +75,7 @@ class PowerManagerService extends IPowerManager.Stub
implements LocalPowerManager, Watchdog.Monitor {
private static final String TAG = "PowerManagerService";
+ private static final String TAGF = "LightFilter";
static final String PARTIAL_NAME = "PowerManagerService";
private static final boolean LOG_PARTIAL_WL = false;
@@ -238,6 +239,34 @@ class PowerManagerService extends IPowerManager.Stub
private int[] mKeyboardBacklightValues;
private int mLightSensorWarmupTime;
+ // Custom light housekeeping
+ private long mLightSettingsTag = -1;
+
+ // Light sensor levels / values
+ private boolean mLightDecrease;
+ private float mLightHysteresis;
+ private boolean mCustomLightEnabled;
+ private int[] mCustomLightLevels;
+ private int[] mCustomLcdValues;
+ private int[] mCustomButtonValues;
+ private int[] mCustomKeyboardValues;
+ private int mLastLcdValue;
+ private int mLastButtonValue;
+ private int mLastKeyboardValue;
+ private int mScreenDim = Power.BRIGHTNESS_DIM;
+ private boolean mAlwaysOnAndDimmed;
+
+ // Light sensor filter, times in milliseconds
+ private boolean mLightFilterEnabled;
+ private boolean mLightFilterRunning;
+ private int mLightFilterSample = -1;
+ private int[] mLightFilterSamples;
+ private int mLightFilterIndex;
+ private int mLightFilterCounter;
+ private int mLightFilterWindow;
+ private int mLightFilterInterval;
+ private int mLightFilterReset;
+
// Used when logging number and duration of touch-down cycles
private long mTotalTouchDownTime;
private long mLastTouchDown;
@@ -422,6 +451,8 @@ class PowerManagerService extends IPowerManager.Stub
// DIM_SCREEN
//mDimScreen = getInt(DIM_SCREEN) != 0;
+ updateLightSettings();
+
// SCREEN_BRIGHTNESS_MODE
setScreenBrightnessMode(getInt(SCREEN_BRIGHTNESS_MODE));
@@ -525,9 +556,10 @@ class PowerManagerService extends IPowerManager.Stub
"(" + Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?) or ("
+ + Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?)",
new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN,
- SCREEN_BRIGHTNESS_MODE},
+ SCREEN_BRIGHTNESS_MODE, Settings.System.LIGHTS_CHANGED},
null);
mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);
SettingsObserver settingsObserver = new SettingsObserver();
@@ -1450,6 +1482,8 @@ class PowerManagerService extends IPowerManager.Stub
mLightSensorValue = -1;
// reset our highest light sensor value when the screen turns off
mHighestLightSensorValue = -1;
+ lightFilterStop();
+ resetLastLightValues();
}
}
}
@@ -1573,6 +1607,7 @@ class PowerManagerService extends IPowerManager.Stub
} else {
// cancel light sensor task
mHandler.removeCallbacks(mAutoBrightnessTask);
+ lightFilterStop();
mScreenOffTime = SystemClock.elapsedRealtime();
long identity = Binder.clearCallingIdentity();
try {
@@ -1687,7 +1722,7 @@ class PowerManagerService extends IPowerManager.Stub
nominalCurrentValue = preferredBrightness;
break;
case SCREEN_ON_BIT:
- nominalCurrentValue = Power.BRIGHTNESS_DIM;
+ nominalCurrentValue = mScreenDim;
break;
case 0:
nominalCurrentValue = Power.BRIGHTNESS_OFF;
@@ -1706,7 +1741,7 @@ class PowerManagerService extends IPowerManager.Stub
// the scale is because the brightness ramp isn't linear and this biases
// it so the later parts take longer.
final float scale = 1.5f;
- float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness);
+ float ratio = (((float)mScreenDim)/preferredBrightness);
if (ratio > 1.0f) ratio = 1.0f;
if ((newState & SCREEN_ON_BIT) == 0) {
if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
@@ -1732,8 +1767,9 @@ class PowerManagerService extends IPowerManager.Stub
// still have a sense of when it is inactive, we
// will then count going dim as turning off.
mScreenOffTime = SystemClock.elapsedRealtime();
+ mAlwaysOnAndDimmed = true;
}
- brightness = Power.BRIGHTNESS_DIM;
+ brightness = mScreenDim;
}
}
long identity = Binder.clearCallingIdentity();
@@ -1916,7 +1952,7 @@ class PowerManagerService extends IPowerManager.Stub
final int brightness = Settings.System.getInt(mContext.getContentResolver(),
SCREEN_BRIGHTNESS);
// Don't let applications turn the screen all the way off
- return Math.max(brightness, Power.BRIGHTNESS_DIM);
+ return Math.max(brightness, mScreenDim);
} catch (SettingNotFoundException snfe) {
return Power.BRIGHTNESS_ON;
}
@@ -2101,11 +2137,41 @@ class PowerManagerService extends IPowerManager.Stub
}
}
- private int getAutoBrightnessValue(int sensorValue, int[] values) {
+ private int getAutoBrightnessValue(int current, int last, int[] levels, int[] values) {
try {
+ // If have a last value and sensor value is decreasing
+ // we should include hysteresis in calculations
+ if (last >= 0 && current < last) {
+ int i;
+ for (i = 0; i < levels.length; i++) {
+ if (last < levels[i]) {
+ break;
+ }
+ }
+ // First sensor level begins at 0 and doesn't have hysteresis
+ if (i > 0) {
+ final int length = levels[i - 1] - (i == 1 ? 0 : levels[i - 2]);
+ final int lower = levels[i - 1] - Math.round(mLightHysteresis * length);
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "level=" + i + " current=" + current + " last=" + last
+ + " length=" + length + " lower=" + lower);
+ }
+ if (current < levels[i - 1] && current >= lower) {
+ // Current sensor value has decreased to the level below but is
+ // still too large due to the hysteresis.
+ // Ignore current to reduce flicker (use last)
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "using last instead of current: " + current
+ + "->" + last);
+ }
+ current = last;
+ }
+ }
+ }
+
int i;
- for (i = 0; i < mAutoBrightnessLevels.length; i++) {
- if (sensorValue < mAutoBrightnessLevels[i]) {
+ for (i = 0; i < levels.length; i++) {
+ if (current < levels[i]) {
break;
}
}
@@ -2143,17 +2209,114 @@ class PowerManagerService extends IPowerManager.Stub
}
};
+ private Runnable mLightFilterTask = new Runnable() {
+ public void run() {
+ synchronized (mLocks) {
+ boolean again = false;
+ if (mLightFilterSample > 0 && !isScreenTurningOffLocked()) {
+ mLightFilterSamples[mLightFilterIndex] = mLightFilterSample;
+ mLightFilterIndex = (mLightFilterIndex + 1) %
+ mLightFilterSamples.length;
+ int sum, count, sample;
+ sum = count = sample = 0;
+ for (int i = 0; i < mLightFilterSamples.length; i++) {
+ sample = mLightFilterSamples[i];
+ if (sample < 0) {
+ break;
+ }
+ sum += sample;
+ count++;
+ }
+ // Count can't be zero here
+ int average = Math.round((float)sum / count);
+ if (average != (int)mLightSensorValue) {
+ lightSensorChangedLocked(average);
+ }
+ if ((int)mLightSensorValue != mLightFilterSample) {
+ again = true;
+ if (mDebugLightSensor) {
+ Slog.d(TAGF, "Tick: " + (int)mLightSensorValue + "::" +
+ mLightFilterSample);
+ }
+ } else if (mDebugLightSensor) {
+ mLightFilterCounter++;
+ again = mLightFilterCounter < mLightFilterSamples.length;
+ Slog.d(TAGF, "Done: " + (int)mLightSensorValue + " " +
+ mLightFilterCounter + "/" + mLightFilterSamples.length);
+ }
+ }
+ if (again) {
+ mHandler.postDelayed(mLightFilterTask, mLightFilterInterval);
+ } else {
+ lightFilterStop();
+ }
+ }
+ }
+ };
+
+ private void lightFilterStop() {
+ if (mDebugLightSensor) {
+ Slog.d(TAGF, "stop");
+ }
+ mLightFilterRunning = false;
+ mHandler.removeCallbacks(mLightFilterTask);
+ mLightFilterSample = -1;
+ }
+
+ private void lightFilterReset(int initial) {
+ mLightFilterCounter = 0;
+ mLightFilterIndex = 0;
+ mLightFilterSamples = new int[(mLightFilterWindow / mLightFilterInterval)];
+ java.util.Arrays.fill(mLightFilterSamples, initial);
+ if (mDebugLightSensor) {
+ Slog.d(TAGF, "reset: " + initial);
+ }
+ }
+
+ private void resetLastLightValues() {
+ mLastLcdValue = -1;
+ mLastButtonValue = -1;
+ mLastKeyboardValue = -1;
+ }
+
+ public int getLightSensorValue() {
+ return (int) mLightSensorValue;
+ }
+
+ public int getRawLightSensorValue() {
+ if (mLightFilterEnabled && mLightFilterSample != -1) {
+ return mLightFilterSample;
+ } else {
+ return getLightSensorValue();
+ }
+ }
+
+ public int getLightSensorScreenBrightness() {
+ return mLightSensorScreenBrightness;
+ }
+
+ public int getLightSensorButtonBrightness() {
+ return mLightSensorButtonBrightness;
+ }
+
+ public int getLightSensorKeyboardBrightness() {
+ return mLightSensorKeyboardBrightness;
+ }
+
private void dockStateChanged(int state) {
synchronized (mLocks) {
mIsDocked = (state != Intent.EXTRA_DOCK_STATE_UNDOCKED);
if (mIsDocked) {
mHighestLightSensorValue = -1;
+ resetLastLightValues();
}
if ((mPowerState & SCREEN_ON_BIT) != 0) {
// force lights recalculation
int value = (int)mLightSensorValue;
mLightSensorValue = -1;
+ resetLastLightValues();
lightSensorChangedLocked(value);
+ lightFilterReset((int)mLightSensorValue);
}
}
}
@@ -2163,8 +2326,12 @@ class PowerManagerService extends IPowerManager.Stub
Slog.d(TAG, "lightSensorChangedLocked " + value);
}
- // do not allow light sensor value to decrease
- if (mHighestLightSensorValue < value) {
+ // do not allow light sensor value to decrease unless the
+ // environment is very dark or user has actively permitted it
+ if (mLightDecrease || value < 200) {
+ mHighestLightSensorValue = value;
+ }
+ else if (mHighestLightSensorValue < value) {
mHighestLightSensorValue = value;
}
@@ -2176,11 +2343,18 @@ class PowerManagerService extends IPowerManager.Stub
// stationary in a dock.
int lcdValue = getAutoBrightnessValue(
(mIsDocked ? value : mHighestLightSensorValue),
- mLcdBacklightValues);
- int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
+ mLastLcdValue,
+ (mCustomLightEnabled ? mCustomLightLevels : mAutoBrightnessLevels),
+ (mCustomLightEnabled ? mCustomLcdValues : mLcdBacklightValues));
+
+ int buttonValue = getAutoBrightnessValue(value, mLastButtonValue,
+ (mCustomLightEnabled ? mCustomLightLevels : mAutoBrightnessLevels),
+ (mCustomLightEnabled ? mCustomButtonValues : mButtonBacklightValues));
int keyboardValue;
if (mKeyboardVisible) {
- keyboardValue = getAutoBrightnessValue(value, mKeyboardBacklightValues);
+ keyboardValue = getAutoBrightnessValue(value, mLastKeyboardValue,
+ (mCustomLightEnabled ? mCustomLightLevels : mAutoBrightnessLevels),
+ (mCustomLightEnabled ? mCustomKeyboardValues : mKeyboardBacklightValues));
} else {
keyboardValue = 0;
}
@@ -2195,18 +2369,29 @@ class PowerManagerService extends IPowerManager.Stub
}
boolean startAnimation = false;
- if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
+ if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0 && !mAlwaysOnAndDimmed) {
if (ANIMATE_SCREEN_LIGHTS) {
if (mScreenBrightness.setTargetLocked(lcdValue,
AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS,
(int)mScreenBrightness.curValue)) {
startAnimation = true;
+ mLastLcdValue = value;
}
} else {
int brightnessMode = (mAutoBrightessEnabled
? LightsService.BRIGHTNESS_MODE_SENSOR
: LightsService.BRIGHTNESS_MODE_USER);
mLcdLight.setBrightness(lcdValue, brightnessMode);
+ mLastLcdValue = value;
+ }
+ // If we don't report brightness correctly stats will be borked
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteScreenBrightness(getPreferredBrightness());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
if (mButtonBrightnessOverride < 0) {
@@ -2215,9 +2400,11 @@ class PowerManagerService extends IPowerManager.Stub
AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
(int)mButtonBrightness.curValue)) {
startAnimation = true;
+ mLastButtonValue = value;
}
} else {
mButtonLight.setBrightness(buttonValue);
+ mLastButtonValue = value;
}
}
if (mButtonBrightnessOverride < 0 || !mKeyboardVisible) {
@@ -2226,9 +2413,11 @@ class PowerManagerService extends IPowerManager.Stub
AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
(int)mKeyboardBrightness.curValue)) {
startAnimation = true;
+ mLastKeyboardValue = value;
}
} else {
mKeyboardLight.setBrightness(keyboardValue);
+ mLastKeyboardValue = value;
}
}
if (startAnimation) {
@@ -2365,6 +2554,7 @@ class PowerManagerService extends IPowerManager.Stub
int value = (int)mLightSensorValue;
mLightSensorValue = -1;
lightSensorChangedLocked(value);
+ lightFilterReset((int)mLightSensorValue);
}
}
userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
@@ -2400,10 +2590,143 @@ class PowerManagerService extends IPowerManager.Stub
if (mLightSensorValue >= 0) {
int value = (int)mLightSensorValue;
mLightSensorValue = -1;
+ resetLastLightValues();
lightSensorChangedLocked(value);
}
+ lightFilterReset((int)mLightSensorValue);
+ if (!enabled) {
+ lightFilterStop();
+ }
+ }
+ }
+ }
+
+ private void updateLightSettings() {
+ ContentResolver cr = mContext.getContentResolver();
+ boolean filterWasEnabled = mLightFilterEnabled;
+
+ long tag = Settings.System.getLong(cr,
+ Settings.System.LIGHTS_CHANGED, 0);
+ if (tag == mLightSettingsTag) {
+ return;
+ }
+ mLightSettingsTag = tag;
+ mCustomLightEnabled = Settings.System.getInt(cr,
+ Settings.System.LIGHT_SENSOR_CUSTOM, 0) != 0;
+ mLightDecrease = Settings.System.getInt(cr,
+ Settings.System.LIGHT_DECREASE, 0) != 0;
+ mLightHysteresis = Settings.System.getInt(cr,
+ Settings.System.LIGHT_HYSTERESIS, 50) / 100f;
+ mLightFilterEnabled = Settings.System.getInt(cr,
+ Settings.System.LIGHT_FILTER, 0) != 0;
+ mLightFilterWindow = Settings.System.getInt(cr,
+ Settings.System.LIGHT_FILTER_WINDOW, 30000);
+ mLightFilterInterval = Settings.System.getInt(cr,
+ Settings.System.LIGHT_FILTER_INTERVAL, 1000);
+ mLightFilterReset = Settings.System.getInt(cr,
+ Settings.System.LIGHT_FILTER_RESET, 800);
+ if (mCustomLightEnabled) {
+ mScreenDim = Settings.System.getInt(cr,
+ Settings.System.LIGHT_SCREEN_DIM, Power.BRIGHTNESS_DIM);
+ } else {
+ mScreenDim = Power.BRIGHTNESS_DIM;
+ }
+
+ if (mLightFilterEnabled) {
+ if (!filterWasEnabled) {
+ lightFilterReset(-1);
}
+ } else {
+ lightFilterStop();
}
+
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "custom: " + mCustomLightEnabled);
+ Slog.d(TAG, "decrease: " + mLightDecrease);
+ Slog.d(TAG, "hysteresis: " + mLightHysteresis);
+ Slog.d(TAG, "filter: " + mLightFilterEnabled);
+ Slog.d(TAG, "window: " + mLightFilterWindow);
+ Slog.d(TAG, "interval: " + mLightFilterInterval);
+ Slog.d(TAG, "reset: " + mLightFilterReset);
+ Slog.d(TAG, "dim: " + mScreenDim);
+ }
+
+ if (mCustomLightEnabled) {
+ // Load custom values
+ try {
+ mCustomLightLevels = parseIntArray(Settings.System.getString(
+ cr, Settings.System.LIGHT_SENSOR_LEVELS));
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "levels: " +
+ java.util.Arrays.toString(mCustomLightLevels));
+ }
+
+ mCustomLcdValues = parseIntArray(Settings.System.getString(
+ cr, Settings.System.LIGHT_SENSOR_LCD_VALUES));
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "lcd values: " +
+ java.util.Arrays.toString(mCustomLcdValues));
+ }
+
+ mCustomButtonValues = parseIntArray(Settings.System.getString(
+ cr, Settings.System.LIGHT_SENSOR_BUTTON_VALUES));
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "button values: " +
+ java.util.Arrays.toString(mCustomButtonValues));
+ }
+
+ mCustomKeyboardValues = parseIntArray(Settings.System.getString(
+ cr, Settings.System.LIGHT_SENSOR_KEYBOARD_VALUES));
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "keyboard values: " +
+ java.util.Arrays.toString(mCustomKeyboardValues));
+ }
+
+ if (mDebugLightSensor) {
+ Slog.d(TAG, "default levels: " +
+ java.util.Arrays.toString(mAutoBrightnessLevels));
+ Slog.d(TAG, "default lcd values: " +
+ java.util.Arrays.toString(mLcdBacklightValues));
+ Slog.d(TAG, "default button values: " +
+ java.util.Arrays.toString(mButtonBacklightValues));
+ Slog.d(TAG, "default keyboard values: " +
+ java.util.Arrays.toString(mKeyboardBacklightValues));
+ }
+
+ // Sanity check
+ int N = mCustomLightLevels.length;
+ if (N < 1 || mCustomLcdValues.length != (N + 1)
+ || mCustomButtonValues.length != (N + 1)
+ || mCustomKeyboardValues.length != (N + 1)) {
+ throw new Exception("sanity check failed");
+ }
+ // force recompute of backlight values
+ if (mLightSensorValue >= 0) {
+ int value = (int)mLightSensorValue;
+ mLightSensorValue = -1;
+ resetLastLightValues();
+ lightSensorChangedLocked(value);
+ }
+ } catch (Exception e) {
+ // Use defaults since we can't trust custom values
+ mCustomLightEnabled = false;
+ Slog.e(TAG, "loading custom settings failed", e);
+ }
+ }
+ }
+
+ private int[] parseIntArray(String intArray) {
+ int[] result;
+ if (intArray == null || intArray.length() == 0) {
+ result = new int[0];
+ } else {
+ String[] split = intArray.split(",");
+ result = new int[split.length];
+ for (int i = 0; i < split.length; i++) {
+ result[i] = Integer.parseInt(split[i]);
+ }
+ }
+ return result;
}
/** Sets the screen off timeouts:
@@ -2606,7 +2929,7 @@ class PowerManagerService extends IPowerManager.Stub
public void setBacklightBrightness(int brightness) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
// Don't let applications turn the screen all the way off
- brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
+ brightness = Math.max(brightness, mScreenDim);
mLcdLight.setBrightness(brightness);
mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0);
mButtonLight.setBrightness(brightness);
@@ -2722,6 +3045,7 @@ class PowerManagerService extends IPowerManager.Stub
mSensorManager.registerListener(mLightListener, mLightSensor,
SensorManager.SENSOR_DELAY_NORMAL);
} else {
+ lightFilterStop();
mSensorManager.unregisterListener(mLightListener);
mHandler.removeCallbacks(mAutoBrightnessTask);
}
@@ -2789,6 +3113,40 @@ class PowerManagerService extends IPowerManager.Stub
Slog.d(TAG, "onSensorChanged: light value: " + value);
}
mHandler.removeCallbacks(mAutoBrightnessTask);
+ mLightFilterSample = value;
+ if (mAutoBrightessEnabled && mLightFilterEnabled) {
+ if (mLightFilterRunning && mLightSensorValue != -1) {
+ // Large changes -> quick response
+ int diff = Math.abs((int)mLightSensorValue - value);
+ if (diff > mLightFilterReset) {
+ if (mDebugLightSensor) {
+ Slog.d(TAGF, "reset cause: " + value +
+ " " + mLightSensorValue + " " + diff);
+ }
+ lightFilterReset(-1);
+ }
+ if (mDebugLightSensor) {
+ Slog.d(TAGF, "sample: " + value);
+ }
+ } else {
+ if (mLightSensorValue == -1 ||
+ milliseconds < mLastScreenOnTime + mLightSensorWarmupTime) {
+ // process the value immediately if screen has just turned on
+ lightFilterReset(-1);
+ lightSensorChangedLocked(value);
+ } else {
+ // Small changes -> filtered
+ lightFilterReset((int)mLightSensorValue);
+ if (mDebugLightSensor) {
+ Slog.d(TAGF, "start: " + value);
+ }
+ mLightFilterRunning = true;
+ mHandler.postDelayed(mLightFilterTask, LIGHT_SENSOR_DELAY);
+ }
+ }
+ return;
+ }
+
if (mLightSensorValue != value) {
if (mLightSensorValue == -1 ||
milliseconds < mLastScreenOnTime + mLightSensorWarmupTime) {
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index a02c4e7..a155f59 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -138,7 +138,7 @@ public class ProcessStats {
private boolean mFirst = true;
- private byte[] mBuffer = new byte[256];
+ private byte[] mBuffer = new byte[1024];
/**
* The time in microseconds that the CPU has been running at each speed.
@@ -502,7 +502,7 @@ public class ProcessStats {
private long[] getCpuSpeedTimes(long[] out) {
long[] tempTimes = out;
long[] tempSpeeds = mCpuSpeeds;
- final int MAX_SPEEDS = 20;
+ final int MAX_SPEEDS = 30;
if (out == null) {
tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
tempSpeeds = new long[MAX_SPEEDS];
@@ -514,20 +514,22 @@ public class ProcessStats {
StringTokenizer st = new StringTokenizer(file, "\n ");
while (st.hasMoreElements()) {
String token = st.nextToken();
- try {
- long val = Long.parseLong(token);
- tempSpeeds[speed] = val;
- token = st.nextToken();
- val = Long.parseLong(token);
- tempTimes[speed] = val;
- speed++;
- if (speed == MAX_SPEEDS) break; // No more
- if (localLOGV && out == null) {
- Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
- + "\t" + tempTimes[speed - 1]);
+ if (st.hasMoreElements()) {
+ try {
+ long val = Long.parseLong(token);
+ tempSpeeds[speed] = val;
+ token = st.nextToken();
+ val = Long.parseLong(token);
+ tempTimes[speed] = val;
+ speed++;
+ if (speed == MAX_SPEEDS) break; // No more
+ if (localLOGV && out == null) {
+ Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
+ + "\t" + tempTimes[speed - 1]);
+ }
+ } catch (NumberFormatException nfe) {
+ Slog.i(TAG, "Unable to parse time_in_state");
}
- } catch (NumberFormatException nfe) {
- Slog.i(TAG, "Unable to parse time_in_state");
}
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9d5d035..b7a7bbf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -39,6 +39,7 @@ import android.os.*;
import android.provider.Contacts.People;
import android.provider.Settings;
import android.server.BluetoothA2dpService;
+import android.server.BluetoothHidService;
import android.server.BluetoothService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
@@ -95,6 +96,7 @@ class ServerThread extends Thread {
WindowManagerService wm = null;
BluetoothService bluetooth = null;
BluetoothA2dpService bluetoothA2dp = null;
+ BluetoothHidService bluetoothHid = null;
HeadsetObserver headset = null;
DockObserver dock = null;
UiModeManagerService uiMode = null;
@@ -193,6 +195,10 @@ class ServerThread extends Thread {
bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
bluetoothA2dp);
+ bluetoothHid = new BluetoothHidService(context, bluetooth);
+ ServiceManager.addService(BluetoothHidService.BLUETOOTH_HID_SERVICE,
+ bluetoothHid);
+ //Log.e(TAG, "Bluetooth HID Service");
int bluetoothOn = Settings.Secure.getInt(mContentResolver,
Settings.Secure.BLUETOOTH_ON, 0);
@@ -442,7 +448,7 @@ class ServerThread extends Thread {
// Enable the JIT for the system_server process
VMRuntime.getRuntime().startJitCompilation();
}
-
+
// It is now time to start up the app processes...
if (devicePolicy != null) {
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index a93a6ee..5b89ee0 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -900,7 +900,12 @@ public class ThrottleService extends IThrottleManager.Stub {
dataFile = new File(throttleDir, imsiHash);
}
// touch the file so it's not LRU
- dataFile.setLastModified(System.currentTimeMillis());
+ if (System.currentTimeMillis() >= 0) {
+ dataFile.setLastModified(System.currentTimeMillis());
+ } else {
+ // system clock is out of whack, but that doesn't mean we can't boot
+ dataFile.setLastModified(Long.MAX_VALUE);
+ }
checkAndDeleteLRUDataFile(throttleDir);
return dataFile;
}
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index 2e7e3e1..379c158 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -123,8 +123,17 @@ public class VibratorService extends IVibratorService.Stub {
return;
}
Vibration vib = new Vibration(token, milliseconds);
+ try {
+ token.linkToDeath(vib, 0);
+ } catch (RemoteException e) {
+ return;
+ }
synchronized (mVibrations) {
removeVibrationLocked(token);
+ if ((mCurrentVibration != null) && (mThread == null)) {
+ mCurrentVibration.mToken.unlinkToDeath(mCurrentVibration, 0);
+ mCurrentVibration = null;
+ }
doCancelVibrateLocked();
mCurrentVibration = vib;
startVibrationLocked(vib);
@@ -174,6 +183,10 @@ public class VibratorService extends IVibratorService.Stub {
synchronized (mVibrations) {
removeVibrationLocked(token);
+ if ((mCurrentVibration != null) && (mThread == null)) {
+ mCurrentVibration.mToken.unlinkToDeath(mCurrentVibration, 0);
+ mCurrentVibration = null;
+ }
doCancelVibrateLocked();
if (repeat >= 0) {
mVibrations.addFirst(vib);
@@ -205,6 +218,10 @@ public class VibratorService extends IVibratorService.Stub {
doCancelVibrateLocked();
startNextVibrationLocked();
}
+ if ((mCurrentVibration != null) && (mThread == null)) {
+ mCurrentVibration.mToken.unlinkToDeath(mCurrentVibration, 0);
+ mCurrentVibration = null;
+ }
}
}
finally {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index a8dad88..0715340 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -64,6 +64,7 @@ import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
@@ -133,6 +134,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import android.graphics.Canvas;
+import android.graphics.Path;
+
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
@@ -387,6 +391,13 @@ public class WindowManagerService extends IWindowManager.Stub
Surface mBlurSurface;
boolean mBlurShown;
+ Surface mMouseSurface;
+ boolean mMouseDisplayed = false;
+ int mMlx;
+ int mMly;
+ int mMlw;
+ int mMlh;
+
int mTransactionSequence = 0;
final float[] mTmpFloats = new float[9];
@@ -2148,6 +2159,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void removeWindowInnerLocked(Session session, WindowState win) {
mKeyWaiter.finishedKey(session, win.mClient, true,
KeyWaiter.RETURN_NOTHING);
+ mKeyWaiter.releaseMotionTarget(win);
mKeyWaiter.releasePendingPointerLocked(win.mSession);
mKeyWaiter.releasePendingTrackballLocked(win.mSession);
@@ -5260,7 +5272,7 @@ public class WindowManagerService extends IWindowManager.Stub
// dispatch the event.
try {
if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
- Slog.v(TAG, "Delivering pointer " + qev + " to " + target);
+ Slog.v(TAG, "Delivering pointer " + qev + " Ev " + ev + " to " + target);
}
if (MEASURE_LATENCY) {
@@ -6119,6 +6131,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ void releaseMotionTarget(WindowState win) {
+ if (mMotionTarget == win) {
+ mMotionTarget = null;
+ }
+ }
+
MotionEvent finishedKey(Session session, IWindow client, boolean force,
int returnWhat) {
if (DEBUG_INPUT) Slog.v(
@@ -6169,7 +6187,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (qev != null) {
res = (MotionEvent)qev.event;
if (DEBUG_INPUT) Slog.v(TAG,
- "Returning pending motion: " + res);
+ "Returning pending motion: " + res + " q: " + qev);
mQueue.recycleEvent(qev);
if (win != null && returnWhat == RETURN_PENDING_POINTER) {
res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
@@ -6394,7 +6412,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (screenIsOff) {
if (!mPolicy.isWakeRelMovementTq(event.deviceId,
device.classes, event)) {
- //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
+ if (DEBUG_INPUT)
+ Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
return false;
}
event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
@@ -6540,7 +6559,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
eventType = eventType((MotionEvent)ev.event);
} else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
- ev.classType == RawInputEvent.CLASS_TRACKBALL) {
+ ev.classType == RawInputEvent.CLASS_TRACKBALL ||
+ ev.classType == RawInputEvent.CLASS_MOUSE) {
eventType = LocalPowerManager.BUTTON_EVENT;
} else {
eventType = LocalPowerManager.OTHER_EVENT;
@@ -6600,6 +6620,44 @@ public class WindowManagerService extends IWindowManager.Stub
case RawInputEvent.CLASS_TOUCHSCREEN:
//Slog.i(TAG, "Read next event " + ev);
dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
+ if (mMouseDisplayed) {
+ Surface.openTransaction();
+ mMouseSurface.hide();
+ Surface.closeTransaction();
+ mMouseDisplayed = false;
+ }
+ break;
+ case RawInputEvent.CLASS_MOUSE:
+ MotionEvent mmev = (MotionEvent)ev.event;
+ int mcx = (int)mmev.getX();
+ int mcy = (int)mmev.getY();
+
+ if (mMouseSurface != null && (mMlx != mcx || mMly != mcy)) {
+ Surface.openTransaction();
+ if (DEBUG_INPUT)
+ Slog.i(TAG, "Open transaction for the mouse surface");
+ WindowState top =
+ (WindowState)mWindows.get(mWindows.size() - 1);
+ try {
+ if (DEBUG_INPUT)
+ Slog.i(TAG, "Move surf, x: " +
+ Integer.toString(mcx) + " y:"
+ + Integer.toString(mcy));
+
+ mMouseSurface.setPosition(mcx, mcy);
+ mMouseSurface.setLayer(top.mAnimLayer + 1);
+ if (!mMouseDisplayed) {
+ mMouseSurface.show();
+ mMouseDisplayed = true;
+ }
+ mMlx = mcx;
+ mMly = mcy;
+ } catch ( RuntimeException e) {
+ Slog.e(TAG, "Failure showing mouse surface",e);
+ }
+ Surface.closeTransaction();
+ }
+ dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
break;
case RawInputEvent.CLASS_TRACKBALL:
dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
@@ -9584,6 +9642,61 @@ public class WindowManagerService extends IWindowManager.Stub
mFxSession = new SurfaceSession();
}
+ if (mMouseSurface == null) {
+ int mMx, mMy, mMw, mMh;
+ Canvas mCanvas;
+ Path mPath = new Path();
+
+ if (DEBUG_INPUT)
+ Slog.i(TAG, "Create Mouse Surface");
+
+ mMw = 12;
+ mMh = 20;
+ mMx = (mDisplay.getWidth() - mMw) / 2;
+ mMy = (mDisplay.getHeight() - mMh) / 2;
+
+ try {
+
+ /*
+ *First Mouse event, create Surface
+ */
+
+ mMouseSurface =
+ new Surface(mFxSession,
+ 0, -1, mMw, mMh,
+ PixelFormat.TRANSPARENT,
+ Surface.FX_SURFACE_NORMAL);
+ mCanvas = mMouseSurface.lockCanvas(null);
+ Paint tPaint = new Paint();
+ tPaint.setStyle(Paint.Style.STROKE);
+ tPaint.setStrokeWidth(2);
+ tPaint.setColor(0xffffffff);
+ mPath.moveTo(0.0f, 0.0f);
+ mPath.lineTo(12.0f, 12.0f);
+ mPath.lineTo(7.0f, 12.0f);
+ mPath.lineTo(11.0f, 20.0f);
+ mPath.lineTo(8.0f, 21.0f);
+ mPath.lineTo(4.0f, 13.0f);
+ mPath.lineTo(0.0f, 17.0f);
+ mPath.close();
+ mCanvas.clipPath(mPath);
+ mCanvas.drawColor(0xff000000);
+ mCanvas.drawPath(mPath, tPaint);
+
+ mMouseSurface.unlockCanvasAndPost(mCanvas);
+ mMouseSurface.openTransaction();
+ mMouseSurface.setSize(mMw, mMh);
+ mMouseSurface.closeTransaction();
+
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception creating mouse surface",e);
+ }
+ mMlx = mMx;
+ mMly = mMy;
+ mMlw = mMw;
+ mMlh = mMh;
+ }
+
if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION");
// Initialize state of exiting tokens.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0c11940..b8b6df7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -52,6 +52,7 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IIntentReceiver;
@@ -1176,7 +1177,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
d.setCancelable(false);
d.setTitle("System UIDs Inconsistent");
d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
- d.setButton("I'm Feeling Lucky",
+ d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
mUidAlert = d;
d.show();
@@ -5879,10 +5880,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
if (pkgs != null) {
for (String pkg : pkgs) {
- if (forceStopPackageLocked(pkg, -1, false, false, false)) {
- setResultCode(Activity.RESULT_OK);
- return;
- }
+ synchronized (ActivityManagerService.this) {
+ if (forceStopPackageLocked(pkg, -1, false, false, false)) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
+ }
}
}
}
@@ -6800,7 +6803,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (localLOGV) Slog.v(
TAG, "getTasks: max=" + maxNum + ", flags=" + flags
+ ", receiver=" + receiver);
-
+ /** This could be bad? Possibly, Might look into better way to do it: Pedlar
if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
!= PackageManager.PERMISSION_GRANTED) {
if (receiver != null) {
@@ -6817,7 +6820,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " requires " + android.Manifest.permission.GET_TASKS;
Slog.w(TAG, msg);
throw new SecurityException(msg);
- }
+ } **/
int pos = mHistory.size()-1;
HistoryRecord next =
@@ -6929,8 +6932,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags) {
synchronized (this) {
- enforceCallingPermission(android.Manifest.permission.GET_TASKS,
- "getRecentTasks()");
+ //enforceCallingPermission(android.Manifest.permission.GET_TASKS,
+ // "getRecentTasks()");
IPackageManager pm = ActivityThread.getPackageManager();
@@ -9044,7 +9047,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
sr.crashCount++;
}
}
-
+
+ // If the crashing process is what we consider to be the "home process" and it has been
+ // replaced by a third-party app, clear the package preferred activities from packages
+ // with a home activity running in the process to prevent a repeatedly crashing app
+ // from blocking the user to manually clear the list.
+ if (app == mHomeProcess && mHomeProcess.activities.size() > 0
+ && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Iterator it = mHomeProcess.activities.iterator();
+ while (it.hasNext()) {
+ HistoryRecord r = (HistoryRecord)it.next();
+ if (r.isHomeActivity) {
+ Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
+ try {
+ ActivityThread.getPackageManager()
+ .clearPackagePreferredActivities(r.packageName);
+ } catch (RemoteException c) {
+ // pm is in same process, this will never happen.
+ }
+ }
+ }
+ }
+
mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
return true;
}
@@ -13814,7 +13838,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int adj;
int schedGroup;
int N;
- if (app == TOP_APP) {
+ if ("com.android.mms".equals(app.processName)) {
+ // MMS can die in situations of heavy memory pressure.
+ // Always push it to the top.
+ adj = FOREGROUND_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.adjType = "mms";
+ } else if (app == TOP_APP) {
// The last app on the list is the foreground app.
adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13856,7 +13886,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} else if (app == mHomeProcess) {
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
- adj = HOME_APP_ADJ;
+ adj = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.LOCK_HOME_IN_MEMORY, 0) == 1 ? VISIBLE_APP_ADJ : HOME_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "home";
} else if ((N=app.activities.size()) != 0) {
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 8e9818d..9fb48b3 100644
--- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.content.Context;
+import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
@@ -49,7 +50,7 @@ class AppWaitingForDebuggerDialog extends BaseErrorDialog {
text.append(" is waiting for the debugger to attach.");
setMessage(text.toString());
- setButton("Force Close", mHandler.obtainMessage(1, app));
+ setButton(DialogInterface.BUTTON_POSITIVE, "Force Close", mHandler.obtainMessage(1, app));
setTitle("Waiting For Debugger");
getWindow().setTitle("Waiting For Debugger: " + app.info.processName);
}
diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java
index 2e25474..b19bb5c 100644
--- a/services/java/com/android/server/am/FactoryErrorDialog.java
+++ b/services/java/com/android/server/am/FactoryErrorDialog.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.content.Context;
+import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
@@ -26,7 +27,8 @@ class FactoryErrorDialog extends BaseErrorDialog {
setCancelable(false);
setTitle(context.getText(com.android.internal.R.string.factorytest_failed));
setMessage(msg);
- setButton(context.getText(com.android.internal.R.string.factorytest_reboot),
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getText(com.android.internal.R.string.factorytest_reboot),
mHandler.obtainMessage(0));
getWindow().setTitle("Factory Error");
}
diff --git a/services/java/com/android/server/status/IconData.java b/services/java/com/android/server/status/IconData.java
index fd226f9..9aaaba1 100644
--- a/services/java/com/android/server/status/IconData.java
+++ b/services/java/com/android/server/status/IconData.java
@@ -16,6 +16,7 @@
package com.android.server.status;
+import android.provider.Settings;
import android.util.Slog;
public class IconData {
@@ -30,8 +31,20 @@ public class IconData {
public static final int ICON = 2;
/**
- * The type of this item. One of TEXT, ICON, or LEVEL_ICON.
+ * Indicates ths item represents an integer displayed on top of an icon.
+ */
+ public static final int ICON_NUMBER = 3;
+
+ /**
+ * Default colors to use for any text appearing on each type of icon.
*/
+ private static final int DEFAULT_TEXT_COLOR = 0xff000000;
+ private static final int DEFAULT_ICON_COLOR = 0xffffffff;
+ private static final int DEFAULT_ICON_NUMBER_COLOR = 0xffffffff;
+
+ /**
+ * The type of this item. One of TEXT, ICON, or LEVEL_ICON.
+ */
public int type;
/**
@@ -65,6 +78,23 @@ public class IconData {
*/
public CharSequence text;
+ /**
+ * The default color of any text associated with this icon.
+ */
+ public int textColor;
+
+ /**
+ * The system setting that holds the text color for this icon.
+ */
+ public String colorSetting;
+
+ /**
+ * The system setting that determines whether the icon is visible or not.
+ * Currently this only applies to the TEXT type.
+ */
+ public String visibleSetting;
+ public boolean defVisibility;
+
private IconData() {
}
@@ -77,14 +107,35 @@ public class IconData {
data.iconId = iconId;
data.iconLevel = iconLevel;
data.number = number;
+ data.textColor = DEFAULT_ICON_COLOR;
+ data.colorSetting = Settings.System.NOTIF_COUNT_COLOR;
return data;
}
- public static IconData makeText(String slot, CharSequence text) {
+ public static IconData makeText(String slot, CharSequence text, String colorSetting,
+ String visibleSetting, boolean defVisibility) {
IconData data = new IconData();
data.type = TEXT;
data.slot = slot;
data.text = text;
+ data.textColor = DEFAULT_TEXT_COLOR;
+ data.colorSetting = colorSetting;
+ data.visibleSetting = visibleSetting;
+ data.defVisibility = defVisibility;
+ return data;
+ }
+
+ public static IconData makeIconNumber(String slot,
+ String iconPackage, int iconId, int iconLevel, int number, String colorSetting) {
+ IconData data = new IconData();
+ data.type = ICON_NUMBER;
+ data.slot = slot;
+ data.iconPackage = iconPackage;
+ data.iconId = iconId;
+ data.iconLevel = iconLevel;
+ data.number = number;
+ data.textColor = DEFAULT_ICON_NUMBER_COLOR;
+ data.colorSetting = colorSetting;
return data;
}
@@ -96,6 +147,10 @@ public class IconData {
this.iconLevel = that.iconLevel;
this.number = that.number;
this.text = that.text; // should we clone this?
+ this.textColor = that.textColor;
+ this.colorSetting = that.colorSetting;
+ this.visibleSetting = that.visibleSetting;
+ this.defVisibility = that.defVisibility;
}
public IconData clone() {
@@ -115,6 +170,14 @@ public class IconData {
+ " iconId=" + Integer.toHexString(this.iconId)
+ " iconLevel=" + this.iconLevel + ")";
}
+
+ else if (this.type == ICON_NUMBER) {
+ return "IconData(slot=" + (this.slot != null ? "'" + this.slot + "'" : "null")
+ + " package=" + this.iconPackage
+ + " iconId=" + Integer.toHexString(this.iconId)
+ + " iconLevel=" + this.iconLevel
+ + " number='" + this.number + "')";
+ }
else {
return "IconData(type=" + type + ")";
}
diff --git a/services/java/com/android/server/status/StatusBarIcon.java b/services/java/com/android/server/status/StatusBarIcon.java
index 6f8b8a8..9f49747 100644
--- a/services/java/com/android/server/status/StatusBarIcon.java
+++ b/services/java/com/android/server/status/StatusBarIcon.java
@@ -30,6 +30,11 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.graphics.drawable.AnimationDrawable;
+import android.provider.Settings;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.util.DisplayMetrics;
class StatusBarIcon {
// TODO: get this from a resource
@@ -44,8 +49,13 @@ class StatusBarIcon {
private TextView mTextView;
private AnimatedImageView mImageView;
private TextView mNumberView;
+ private int clockColor = 0xff000000;
+ private int batteryPercentColor = 0xffffffff;
+ private int notifCountColor = 0xffffffff;
+ private Context mContext;
public StatusBarIcon(Context context, IconData data, ViewGroup parent) {
+ mContext = context;
mData = data.clone();
switch (data.type) {
@@ -55,15 +65,25 @@ class StatusBarIcon {
mTextView = t;
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.MATCH_PARENT);
+ LinearLayout.LayoutParams.FILL_PARENT);
t.setTextSize(16);
- t.setTextColor(0xff000000);
t.setTypeface(Typeface.DEFAULT_BOLD);
t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
t.setPadding(6, 0, 0, 0);
t.setLayoutParams(layoutParams);
t.setText(data.text);
this.view = t;
+
+ data.textColor = Settings.System.getInt(mContext.getContentResolver(), data.colorSetting, data.textColor);
+ t.setTextColor(data.textColor);
+
+ if (getBoolean(context, data.visibleSetting, data.defVisibility)) {
+ t.setVisibility(View.VISIBLE);
+ }
+ else {
+ t.setVisibility(View.GONE);
+ }
+
break;
}
@@ -85,12 +105,71 @@ class StatusBarIcon {
mNumberView = nv;
if (data.number > 0) {
nv.setText("" + data.number);
+ data.textColor = Settings.System.getInt(mContext.getContentResolver(),
+ data.colorSetting, data.textColor);
+ nv.setTextColor(data.textColor);
nv.setVisibility(View.VISIBLE);
} else {
nv.setVisibility(View.GONE);
}
break;
}
+ case IconData.ICON_NUMBER: {
+ // container
+ LayoutInflater inflater = (LayoutInflater)context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View v = inflater.inflate(com.android.internal.R.layout.status_bar_icon, parent, false);
+ this.view = v;
+
+ // icon
+ AnimatedImageView im = (AnimatedImageView)v.findViewById(com.android.internal.R.id.image);
+ im.setImageDrawable(getIcon(context, data));
+ im.setImageLevel(data.iconLevel);
+ mImageView = im;
+
+ // number
+ TextView nv = (TextView)v.findViewById(com.android.internal.R.id.number);
+ mNumberView = nv;
+
+ //remove background, center, and change gravity of text
+ // attempt to correct position on both hdpi and mdpi
+ DisplayMetrics dm = new DisplayMetrics();
+ ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(dm);
+
+ if (DisplayMetrics.DENSITY_HIGH == dm.densityDpi) {
+ mNumberView.setLayoutParams(
+ new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.RIGHT | Gravity.CENTER_VERTICAL));
+
+ mNumberView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
+ }
+ else {
+ mNumberView.setLayoutParams(
+ new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER | Gravity.CENTER_VERTICAL));
+
+ mNumberView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
+ }
+
+ mNumberView.setBackgroundDrawable(null);
+ data.textColor = Settings.System.getInt(context.getContentResolver(),
+ data.colorSetting, data.textColor);
+ mNumberView.setTextColor(data.textColor);
+ mNumberView.setTextSize(12);
+
+ if (data.number == 100) {
+ nv.setText("" + 99);
+ } else if ((data.number > 0)&&(data.number < 100)) {
+ nv.setText("" + data.number);
+ } else {
+ nv.setText("");
+ }
+ break;
+ }
}
}
@@ -100,12 +179,16 @@ class StatusBarIcon {
}
switch (data.type) {
case IconData.TEXT:
+ data.textColor = Settings.System.getInt(mContext.getContentResolver(),
+ data.colorSetting, data.textColor);
+ mTextView.setTextColor(data.textColor);
if (!TextUtils.equals(mData.text, data.text)) {
TextView tv = mTextView;
tv.setText(data.text);
}
break;
case IconData.ICON:
+ case IconData.ICON_NUMBER:
if (((mData.iconPackage != null && data.iconPackage != null)
&& !mData.iconPackage.equals(data.iconPackage))
|| mData.iconId != data.iconId
@@ -114,6 +197,9 @@ class StatusBarIcon {
im.setImageDrawable(getIcon(context, data));
im.setImageLevel(data.iconLevel);
}
+ data.textColor = Settings.System.getInt(mContext.getContentResolver(),
+ data.colorSetting, data.textColor);
+ mNumberView.setTextColor(data.textColor);
if (mData.number != data.number) {
TextView nv = mNumberView;
if (data.number > 0) {
@@ -182,5 +268,8 @@ class StatusBarIcon {
int getNumber() {
return mData.number;
}
+ private boolean getBoolean(Context context, String systemSettingKey, boolean defaultValue) {
+ return 1 == android.provider.Settings.System.getInt(context.getContentResolver(), systemSettingKey, defaultValue ? 1 : 0);
+ }
}
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 94d1cb4..1fd72e6 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -20,6 +20,7 @@ import android.app.AlertDialog;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHid;
import android.bluetooth.BluetoothPbap;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -121,6 +122,9 @@ public class StatusBarPolicy {
//***** Signal strength icons
private IconData mPhoneData;
+ private IBinder mPhoneDbmIcon;
+ private IconData mPhoneDbmData;
+
//GSM/UMTS
private static final int[] sSignalImages = new int[] {
com.android.internal.R.drawable.stat_sys_signal_0,
@@ -299,6 +303,7 @@ public class StatusBarPolicy {
private IconData mBluetoothData;
private int mBluetoothHeadsetState;
private boolean mBluetoothA2dpConnected;
+ private int mBluetoothHidState;
private int mBluetoothPbapState;
private boolean mBluetoothEnabled;
@@ -381,6 +386,7 @@ public class StatusBarPolicy {
}
else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
action.equals(BluetoothHeadset.ACTION_STATE_CHANGED) ||
+ action.equals(BluetoothHid.HID_DEVICE_STATE_CHANGED_ACTION) ||
action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED) ||
action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
updateBluetooth(intent);
@@ -415,7 +421,7 @@ public class StatusBarPolicy {
// clock
mCalendar = Calendar.getInstance(TimeZone.getDefault());
- mClockData = IconData.makeText("clock", "");
+ mClockData = IconData.makeText("clock", "", Settings.System.CLOCK_COLOR, Settings.System.SHOW_STATUS_CLOCK, true);
mClockIcon = service.addIcon(mClockData, null);
updateClock();
@@ -425,8 +431,9 @@ public class StatusBarPolicy {
new com.android.server.status.StorageNotification(context));
// battery
- mBatteryData = IconData.makeIcon("battery",
- null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
+ mBatteryData = IconData.makeIconNumber("battery",
+ null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0,
+ Settings.System.BATTERY_PERCENTAGE_STATUS_COLOR);
mBatteryIcon = service.addIcon(mBatteryData, null);
// phone_signal
@@ -435,6 +442,10 @@ public class StatusBarPolicy {
null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
mPhoneIcon = service.addIcon(mPhoneData, null);
+ // dbm signal level
+ mPhoneDbmData = IconData.makeText("phone_dbm_signal", "", Settings.System.DBM_COLOR, Settings.System.SHOW_STATUS_DBM, false);
+ mPhoneDbmIcon = service.addIcon(mPhoneDbmData, null);
+
// register for phone state notifications.
((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
.listen(mPhoneStateListener,
@@ -488,8 +499,14 @@ public class StatusBarPolicy {
null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
mGpsFixIconData = IconData.makeIcon("gps",
null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
- mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
- service.setIconVisibility(mGpsIcon, false);
+ ContentResolver resolver = mContext.getContentResolver();
+ String allowedProviders = Settings.Secure.getString(resolver,
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
+ if((allowedProviders.equalsIgnoreCase("gps")) || (allowedProviders.equalsIgnoreCase("network")))
+ {
+ mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
+ service.setIconVisibility(mGpsIcon, false);
+ }
// Alarm clock
mAlarmClockIconData = IconData.makeIcon(
@@ -530,6 +547,7 @@ public class StatusBarPolicy {
filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
+ filter.addAction(BluetoothHid.HID_DEVICE_STATE_CHANGED_ACTION);
filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
@@ -562,7 +580,12 @@ public class StatusBarPolicy {
if (b24) {
res = R.string.twenty_four_hour_time_format;
} else {
- res = R.string.twelve_hour_time_format;
+ if (Settings.System.getInt(mContext.getContentResolver(), Settings.System.SHOW_TWELVE_HOUR_CLOCK_PERIOD, 1) == 1) {
+ res = R.string.twelve_hour_time_format;
+ }
+ else {
+ res = R.string.twelve_hour_time_format_no_period;
+ }
}
final char MAGIC1 = '\uEF00';
@@ -648,10 +671,21 @@ public class StatusBarPolicy {
private final void updateBattery(Intent intent) {
mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
mBatteryData.iconLevel = intent.getIntExtra("level", 0);
- mService.updateIcon(mBatteryIcon, mBatteryData, null);
boolean plugged = intent.getIntExtra("plugged", 0) != 0;
int level = intent.getIntExtra("level", -1);
+
+ //show battery percentage if not plugged in and status is enabled
+ if (plugged || level >= 100 ||
+ Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.BATTERY_PERCENTAGE_STATUS_ICON, 0) == 0) {
+ mBatteryData.number = -1;
+ } else {
+ mBatteryData.number = level;
+ }
+
+ mService.updateIcon(mBatteryIcon, mBatteryData, null);
+
if (false) {
Slog.d(TAG, "updateBattery level=" + level
+ " plugged=" + plugged
@@ -973,6 +1007,7 @@ public class StatusBarPolicy {
private final void updateSignalStrength() {
int iconLevel = -1;
+ int dBm = 0;
int[] iconList;
// Display signal strength while in "emergency calls only" mode
@@ -985,6 +1020,7 @@ public class StatusBarPolicy {
mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
}
mService.updateIcon(mPhoneIcon, mPhoneData, null);
+ mService.updateIcon(mPhoneDbmIcon, mPhoneDbmData, null);
return;
}
@@ -1001,6 +1037,10 @@ public class StatusBarPolicy {
else if (asu >= 5) iconLevel = 2;
else iconLevel = 1;
+ if (asu != 99) {
+ dBm = asu * 2 - 113;
+ }
+
// Though mPhone is a Manager, this call is not an IPC
if (mPhone.isNetworkRoaming()) {
iconList = sSignalImages_r;
@@ -1015,15 +1055,19 @@ public class StatusBarPolicy {
// If a voice call is made then RSSI should switch to 1x.
if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
iconLevel = getEvdoLevel();
+ dBm = mSignalStrength.getEvdoDbm();
if (false) {
Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
}
} else {
iconLevel = getCdmaLevel();
+ dBm = mSignalStrength.getCdmaDbm();
}
}
mPhoneData.iconId = iconList[iconLevel];
mService.updateIcon(mPhoneIcon, mPhoneData, null);
+ mPhoneDbmData.text = Integer.toString(dBm);
+ mService.updateIcon(mPhoneDbmIcon, mPhoneDbmData, null);
}
private int getCdmaLevel() {
@@ -1212,11 +1256,15 @@ public class StatusBarPolicy {
} else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
BluetoothPbap.STATE_DISCONNECTED);
+ } else if (action.equals(BluetoothHid.HID_DEVICE_STATE_CHANGED_ACTION)) {
+ mBluetoothHidState = intent.getIntExtra(BluetoothHid.HID_DEVICE_STATE,
+ BluetoothHid.STATE_DISCONNECTED);
} else {
return;
}
if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpConnected ||
+ mBluetoothHidState == BluetoothHid.STATE_CONNECTED ||
mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
}
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 93c8d34..df7c689 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -41,6 +41,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Telephony;
+import android.util.Log;
import android.util.Slog;
import android.view.Display;
import android.view.Gravity;
@@ -55,6 +56,7 @@ import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.ScrollView;
@@ -67,6 +69,12 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
+import android.provider.Settings;
+import java.lang.reflect.Field;
+
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.StateListDrawable;
+
/**
* The public (ok, semi-public) service for the status bar.
@@ -88,6 +96,9 @@ public class StatusBarService extends IStatusBar.Stub
static final String TAG = "StatusBar";
static final boolean SPEW = false;
+ private boolean mShowPlmnSb;
+ private boolean mShowSpnSb;
+
static final int EXPANDED_LEAVE_ALONE = -10000;
static final int EXPANDED_FULL_OPEN = -10001;
@@ -101,6 +112,7 @@ public class StatusBarService extends IStatusBar.Stub
private static final int OP_EXPAND = 5;
private static final int OP_TOGGLE = 6;
private static final int OP_DISABLE = 7;
+
private class PendingOp {
IBinder key;
int code;
@@ -206,6 +218,7 @@ public class StatusBarService extends IStatusBar.Stub
private Ticker mTicker;
private View mTickerView;
private boolean mTicking;
+ private TickerView tickerView;
// Tracking finger for opening/closing.
int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
@@ -224,6 +237,22 @@ public class StatusBarService extends IStatusBar.Stub
boolean mAnimatingReveal = false;
int mViewDelta;
int[] mAbsPos = new int[2];
+ private int blackColor = 0xff000000;
+ private int whiteColor = 0xffffffff;
+ private int notificationTitleColor = blackColor;
+ private int notificationTextColor = blackColor;
+ private int notificationTimeColor = blackColor;
+ boolean custNotBar = false;
+ boolean custExpBar = false;
+ int notifBarColorMask;
+ int expBarColorMask;
+ Mode notifPDMode = Mode.SCREEN;
+ Mode expPDMode = Mode.SCREEN;
+ Drawable closerDrawable;
+ Drawable expBarBackDrawable;
+ Drawable expBarHeadDrawable;
+ Drawable expBarNotifTitleDrawable;
+
// for disabling the status bar
ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
@@ -234,9 +263,13 @@ public class StatusBarService extends IStatusBar.Stub
*/
public StatusBarService(Context context) {
mContext = context;
+ notificationTitleColor = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NOTIF_ITEM_TITLE_COLOR, blackColor);
+ notificationTextColor = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NOTIF_ITEM_TEXT_COLOR, blackColor);
+ notificationTimeColor = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NOTIF_ITEM_TIME_COLOR, blackColor);
mDisplay = ((WindowManager)context.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
makeStatusBarView(context);
+ updateColors();
mUninstallReceiver = new UninstallReceiver();
}
@@ -251,7 +284,7 @@ public class StatusBarService extends IStatusBar.Stub
Resources res = context.getResources();
mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order);
mRightIcons = new StatusBarIcon[mRightIconSlots.length];
-
+ getNotBarConfig();
ExpandedView expanded = (ExpandedView)View.inflate(context,
com.android.internal.R.layout.status_bar_expanded, null);
expanded.mService = this;
@@ -265,14 +298,23 @@ public class StatusBarService extends IStatusBar.Stub
if (bg != null) {
mPixelFormat = bg.getOpacity();
}
-
mStatusBarView = sb;
+ mDateView = (DateView)sb.findViewById(R.id.date);
+
+ if (custNotBar) {
+ mStatusBarView.setBackgroundDrawable(res.getDrawable(com.android.internal.R.drawable.statusbar_background_sq,
+ notifBarColorMask, notifPDMode));
+ mDateView.setBackgroundDrawable(res.getDrawable(com.android.internal.R.drawable.statusbar_background_sq,
+ notifBarColorMask, notifPDMode));
+ mDateView.setPadding(6, 0, 6, 0);
+ }
+
mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
mNotificationIcons.service = this;
mIcons = (LinearLayout)sb.findViewById(R.id.icons);
mTickerView = sb.findViewById(R.id.ticker);
- mDateView = (DateView)sb.findViewById(R.id.date);
+
mExpandedDialog = new ExpandedDialog(context);
mExpandedView = expanded;
@@ -288,21 +330,33 @@ public class StatusBarService extends IStatusBar.Stub
mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel);
mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
-
+ if (custExpBar) {
+ mExpandedView.findViewById(R.id.exp_view_lin_layout).
+ setBackgroundDrawable(expBarHeadDrawable);
+ mNoNotificationsTitle.setBackgroundDrawable(expBarNotifTitleDrawable);
+ mOngoingTitle.setBackgroundDrawable(expBarNotifTitleDrawable);
+ mLatestTitle.setBackgroundDrawable(expBarNotifTitleDrawable);
+ }
mOngoingTitle.setVisibility(View.GONE);
mLatestTitle.setVisibility(View.GONE);
mTicker = new MyTicker(context, sb);
- TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
+ tickerView = (TickerView)sb.findViewById(R.id.tickerText);
tickerView.mTicker = mTicker;
mTrackingView = (TrackingView)View.inflate(context,
com.android.internal.R.layout.status_bar_tracking, null);
mTrackingView.mService = this;
mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
+ if (custExpBar) {
+ ImageView iv = (ImageView)mTrackingView.findViewById(R.id.close_image);
+ mCloseView.removeAllViews();
+ iv.setImageDrawable(closerDrawable);
+ iv.setColorFilter(expBarColorMask, expPDMode);
+ mCloseView.addView(iv);
+ }
mCloseView.mService = this;
-
mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
// add the more icon for the notifications
@@ -828,7 +882,8 @@ public class StatusBarService extends IStatusBar.Stub
};
View makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
- NotificationData n = notification.data;
+ Resources res = mContext.getResources();
+ NotificationData n = notification.data;
RemoteViews remoteViews = n.contentView;
if (remoteViews == null) {
return null;
@@ -838,9 +893,22 @@ public class StatusBarService extends IStatusBar.Stub
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(com.android.internal.R.layout.status_bar_latest_event, parent, false);
-
- // bind the click event to the content area
ViewGroup content = (ViewGroup)row.findViewById(com.android.internal.R.id.content);
+ if (custExpBar) {
+ StateListDrawable sld = new StateListDrawable();
+ int stateFocused = android.R.attr.state_focused;
+ int statePressed = android.R.attr.state_pressed;
+ Drawable colornormal = res.getDrawable(com.android.internal.R.drawable.status_bar_item_background_normal_cust);
+ Drawable colorfocused = res.getDrawable(com.android.internal.R.drawable.status_bar_item_background_focus_cust);
+ Drawable colorpressed = res.getDrawable(com.android.internal.R.drawable.status_bar_item_background_pressed_cust);
+ sld.addState(new int[] {stateFocused}, colorfocused);
+ sld.addState(new int[] {statePressed}, colorpressed);
+ sld.addState(new int[] {}, colornormal);
+ sld.mutate();
+ sld.setColorFilter(expBarColorMask, expPDMode);
+ content.setBackgroundDrawable(sld);
+
+ }
content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
content.setOnFocusChangeListener(mFocusChangeListener);
PendingIntent contentIntent = n.contentIntent;
@@ -860,7 +928,12 @@ public class StatusBarService extends IStatusBar.Stub
Slog.e(TAG, "couldn't inflate view for package " + n.pkg, exception);
return null;
}
- content.addView(child);
+
+ // This will try to handle text color for all notifications from apps, applying the appropriate
+ // color if ID is possible, otherwise setting it to notification text color
+ startRecurse(child);
+
+ content.addView(child);
row.setDrawingCacheEnabled(true);
@@ -870,6 +943,43 @@ public class StatusBarService extends IStatusBar.Stub
return row;
}
+ void startRecurse(View v) {
+ ViewGroup vg = (ViewGroup) v;
+ int childcount = vg.getChildCount();
+ if (childcount > 0) {
+ int i;
+ for (i = 0; i < childcount; i++) {
+ try {
+ setViewColors((TextView) vg.getChildAt(i));
+ } catch (Exception e) { }
+ try {
+ startRecurse((View) vg.getChildAt(i));
+ } catch (Exception e) { }
+ }
+ }
+ }
+
+ void setViewColors(TextView tv) {
+ int tvID = 0;
+ try {
+ tvID = tv.getId();
+ switch (tvID) {
+ case com.android.internal.R.id.title:
+ tv.setTextColor(notificationTitleColor);
+ break;
+ case com.android.internal.R.id.text:
+ tv.setTextColor(notificationTextColor);
+ break;
+ case com.android.internal.R.id.time:
+ tv.setTextColor(notificationTimeColor);
+ break;
+ default:
+ tv.setTextColor(notificationTextColor);
+ }
+ } catch (Exception e) { }
+ }
+
+
void addNotificationView(StatusBarNotification notification) {
if (notification.view != null) {
throw new RuntimeException("Assertion failed: notification.view="
@@ -1510,7 +1620,7 @@ public class StatusBarService extends IStatusBar.Stub
Drawable bg;
/// ---------- Tracking View --------------
- pixelFormat = PixelFormat.RGBX_8888;
+ pixelFormat = PixelFormat.TRANSLUCENT;
bg = mTrackingView.getBackground();
if (bg != null) {
pixelFormat = bg.getOpacity();
@@ -1730,6 +1840,17 @@ public class StatusBarService extends IStatusBar.Stub
}
}
}
+
+ private void updateColors() {
+ mDateView.setTextColor(Settings.System.getInt(mContext.getContentResolver(), Settings.System.DATE_COLOR, blackColor));
+ mNoNotificationsTitle.setTextColor(Settings.System.getInt(mContext.getContentResolver(), Settings.System.NO_NOTIF_COLOR, whiteColor));
+ mLatestTitle.setTextColor(Settings.System.getInt(mContext.getContentResolver(), Settings.System.LATEST_NOTIF_COLOR, whiteColor));
+ mOngoingTitle.setTextColor(Settings.System.getInt(mContext.getContentResolver(), Settings.System.ONGOING_NOTIF_COLOR, whiteColor));
+ mSpnLabel.setTextColor(Settings.System.getInt(mContext.getContentResolver(), Settings.System.SPN_LABEL_COLOR, blackColor));
+ mPlmnLabel.setTextColor(Settings.System.getInt(mContext.getContentResolver(), Settings.System.PLMN_LABEL_COLOR, blackColor));
+ mClearButton.setTextColor(Settings.System.getInt(mContext.getContentResolver(), Settings.System.CLEAR_BUTTON_LABEL_COLOR, blackColor));
+ tickerView.updateColors(Settings.System.getInt(mContext.getContentResolver(), Settings.System.NEW_NOTIF_TICKER_COLOR, blackColor));
+ }
private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
public void onClick(View v) {
@@ -1737,7 +1858,7 @@ public class StatusBarService extends IStatusBar.Stub
addPendingOp(OP_EXPAND, null, false);
}
};
-
+
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -1758,12 +1879,16 @@ public class StatusBarService extends IStatusBar.Stub
};
void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+ // Double carrier
+ mShowPlmnSb = (Settings.System.getInt(mContext.getContentResolver(), Settings.System.SHOW_PLMN_SB, 1) == 1);
+ mShowSpnSb = (Settings.System.getInt(mContext.getContentResolver(), Settings.System.SHOW_SPN_SB, 1) == 1);
if (false) {
Slog.d(TAG, "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+ " showPlmn=" + showPlmn + " plmn=" + plmn);
}
boolean something = false;
- if (showPlmn) {
+ // Double carrier - bcrook
+ if (showPlmn && mShowPlmnSb) {
mPlmnLabel.setVisibility(View.VISIBLE);
if (plmn != null) {
mPlmnLabel.setText(plmn);
@@ -1774,7 +1899,8 @@ public class StatusBarService extends IStatusBar.Stub
mPlmnLabel.setText("");
mPlmnLabel.setVisibility(View.GONE);
}
- if (showSpn && spn != null) {
+ // Double carrier - bcrook, refinements from Wysie
+ if (showSpn && spn != null && mShowSpnSb) {
mSpnLabel.setText(spn);
mSpnLabel.setVisibility(View.VISIBLE);
something = true;
@@ -1878,4 +2004,38 @@ public class StatusBarService extends IStatusBar.Stub
}
}
}
+
+ private void getNotBarConfig() {
+ Resources res = mContext.getResources();
+ /*
+ * Setup color and bar type for notification strip
+ */
+ boolean useCustom = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NOTIF_BAR_CUSTOM, 0) == 1;
+ notifBarColorMask = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NOTIF_BAR_COLOR, whiteColor);
+ if (useCustom) {
+ custNotBar = true;
+ } else {
+ custNotBar = false;
+ }
+ /*
+ * Setup colors for expanded notification drawables
+ */
+ boolean useCustomExp = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NOTIF_EXPANDED_BAR_CUSTOM, 0) == 1;
+ expBarColorMask = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NOTIF_EXPANDED_BAR_COLOR, whiteColor);
+ int noalpha = expBarColorMask | 0xFF000000;
+ if (useCustomExp) {
+ closerDrawable = res.getDrawable(com.android.internal.R.drawable.status_bar_close_on_cust);
+ expBarHeadDrawable = res.getDrawable(com.android.internal.R.drawable.status_bar_header_background_cust,
+ expBarColorMask, expPDMode);
+ expBarNotifTitleDrawable = res.getDrawable(com.android.internal.R.drawable.title_bar_portrait_cust,
+ noalpha, expPDMode); // always solid
+ custExpBar = true;
+ } else {
+ custExpBar = false;
+ }
+ }
}
diff --git a/services/java/com/android/server/status/TickerView.java b/services/java/com/android/server/status/TickerView.java
index 099dffb..40e1462 100644
--- a/services/java/com/android/server/status/TickerView.java
+++ b/services/java/com/android/server/status/TickerView.java
@@ -19,11 +19,13 @@ package com.android.server.status;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextSwitcher;
+import android.widget.TextView;
public class TickerView extends TextSwitcher
{
Ticker mTicker;
+ private int textColor = 0xFF000000;
public TickerView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -34,5 +36,24 @@ public class TickerView extends TextSwitcher
super.onSizeChanged(w, h, oldw, oldh);
mTicker.reflowText();
}
+
+ @Override
+ public void setText(CharSequence text) {
+ final TextView t = (TextView) getNextView();
+ t.setTextColor(textColor);
+ t.setText(text);
+ showNext();
+ }
+
+ @Override
+ public void setCurrentText(CharSequence text) {
+ final TextView t = (TextView) getCurrentView();
+ t.setTextColor(textColor);
+ t.setText(text);
+ }
+
+ public void updateColors(int color) {
+ textColor = color;
+ }
}
diff --git a/services/java/com/android/server/status/TrackingPatternView.java b/services/java/com/android/server/status/TrackingPatternView.java
index 2c91aa4..46648af 100644
--- a/services/java/com/android/server/status/TrackingPatternView.java
+++ b/services/java/com/android/server/status/TrackingPatternView.java
@@ -17,7 +17,9 @@
package com.android.server.status;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Slog;
import android.view.View;
@@ -25,6 +27,10 @@ import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.BitmapDrawable;
+
public class TrackingPatternView extends View {
private Bitmap mTexture;
@@ -34,9 +40,7 @@ public class TrackingPatternView extends View {
public TrackingPatternView(Context context, AttributeSet attrs) {
super(context, attrs);
-
- mTexture = BitmapFactory.decodeResource(getResources(),
- com.android.internal.R.drawable.status_bar_background);
+ setTexture();
mTextureWidth = mTexture.getWidth();
mTextureHeight = mTexture.getHeight();
@@ -67,4 +71,21 @@ public class TrackingPatternView extends View {
x += textureWidth;
}
}
+
+ private void setTexture() {
+ boolean useCustomExp = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NOTIF_EXPANDED_BAR_CUSTOM, 0) == 1;
+ int expBarColorMask = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NOTIF_EXPANDED_BAR_COLOR, 0xFF000000);
+ if (useCustomExp) {
+ Bitmap tempbm = BitmapFactory.decodeResource(getResources(),
+ com.android.internal.R.drawable.status_bar_background_cust);
+ Bitmap mutable = Bitmap.createBitmap(tempbm.getWidth(), tempbm.getHeight(), Bitmap.Config.ARGB_8888);
+ mutable.eraseColor(expBarColorMask);
+ mTexture = mutable;
+ } else {
+ mTexture = BitmapFactory.decodeResource(getResources(),
+ com.android.internal.R.drawable.status_bar_background);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 55d25a5..3824780 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -55,6 +55,12 @@ public class PhoneNumberUtils
public static final char WILD = 'N';
/*
+ * Calling Line Identification Restriction (CLIR)
+ */
+ private static final String CLIR_ON = "*31#+";
+ private static final String CLIR_OFF = "#31#+";
+
+ /*
* TOA = TON + NPI
* See TS 24.008 section 10.5.4.7 for details.
* These are the only really useful TOA values
@@ -179,8 +185,6 @@ public class PhoneNumberUtils
* Please note that the GSM wild character is allowed in the result.
* This must be resolved before dialing.
*
- * Allows + only in the first position in the result string.
- *
* Returns null if phoneNumber == null
*/
public static String
@@ -203,6 +207,11 @@ public class PhoneNumberUtils
}
}
+ int pos = addPlusChar(phoneNumber);
+ if (pos >= 0 && ret.length() > pos) {
+ ret.insert(pos, '+');
+ }
+
return ret.toString();
}
@@ -304,6 +313,28 @@ public class PhoneNumberUtils
}
}
+ /** GSM codes
+ * Finds if a GSM code includes the international prefix (+).
+ *
+ * @param number the number to dial.
+ *
+ * @return the position where the + char will be inserted, -1 if the GSM code was not found.
+ */
+ private static int
+ addPlusChar(String number) {
+ int pos = -1;
+
+ if (number.startsWith(CLIR_OFF)) {
+ pos = CLIR_OFF.length() - 1;
+ }
+
+ if (number.startsWith(CLIR_ON)) {
+ pos = CLIR_ON.length() - 1;
+ }
+
+ return pos;
+ }
+
/**
* Extracts the post-dial sequence of DTMF control digits, pauses, and
* waits. Strips separators. This string may be empty, but will not be null
diff --git a/telephony/java/com/android/internal/telephony/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
index c8c0658..a175d49 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecordCache.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
@@ -186,7 +186,12 @@ public final class AdnRecordCache extends Handler implements IccConstants {
}
ArrayList<AdnRecord> oldAdnList;
- oldAdnList = getRecordsIfLoaded(efid);
+
+ if (efid == EF_PBR) {
+ oldAdnList = mUsimPhoneBookManager.loadEfFilesFromUsim();
+ } else {
+ oldAdnList = getRecordsIfLoaded(efid);
+ }
if (oldAdnList == null) {
sendErrorResponse(response, "Adn list not exist for EF:" + efid);
@@ -208,6 +213,17 @@ public final class AdnRecordCache extends Handler implements IccConstants {
return;
}
+ if (efid == EF_PBR) {
+ AdnRecord foundAdn = oldAdnList.get(index-1);
+ efid = foundAdn.efid;
+ extensionEF = foundAdn.extRecord;
+ index = foundAdn.recordNumber;
+
+ newAdn.efid = efid;
+ newAdn.extRecord = extensionEF;
+ newAdn.recordNumber = index;
+ }
+
Message pendingResponse = userWriteResponse.get(efid);
if (pendingResponse != null) {
@@ -331,6 +347,7 @@ public final class AdnRecordCache extends Handler implements IccConstants {
if (ar.exception == null) {
adnLikeFiles.get(efid).set(index - 1, adn);
+ mUsimPhoneBookManager.invalidateCache();
}
Message response = userWriteResponse.get(efid);
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 9f8e57f..176b087 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -144,6 +144,9 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
if (DBG) logd("updateAdnRecordsInEfBySearch: efid=" + efid +
" ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" +
" ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2);
+
+ efid = updateEfForIccType(efid);
+
synchronized(mLock) {
checkThread();
success = false;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 627d94d..92a6173 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -443,7 +443,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if ((state == State.IDLE || state == State.SCANNING)
&& (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
&& mGsmPhone.mSIMRecords.getRecordsLoaded()
- && phone.getState() == Phone.State.IDLE
+ && (mGsmPhone.mSST.isConcurrentVoiceAndData() ||
+ phone.getState() == Phone.State.IDLE )
&& isDataAllowed()
&& !mIsPsRestricted
&& desiredPowerState ) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index bcbd127..6a65b87 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -124,8 +124,12 @@ public final class GsmMmiCode extends Handler implements MmiCode {
// See TS 22.030 6.5.2 "Structure of the MMI"
+ // Note that some nonstandard MMI codes seem to end with an asterisk, eg. "#190*1660#*"
+ // (http://code.google.com/p/android/issues/detail?id=2226). Make sure this doesn't get
+ // merged into MATCH_GROUP_DIALING_NUMBER.
+
static Pattern sPatternSuppService = Pattern.compile(
- "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
+ "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#\\*?)(.*)");
/* 1 2 3 4 5 6 7 8 9 10 11 12
1 = Full string up to and including #
@@ -134,7 +138,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
5 = SIA
7 = SIB
9 = SIC
- 10 = dialing number
+ 12 = dialing number
*/
static final int MATCH_GROUP_POUND_STRING = 1;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index d711a80..b4e7b63 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -559,6 +559,13 @@ public final class SIMRecords extends IccRecords {
break;
case EVENT_GET_CPHS_MAILBOX_DONE:
case EVENT_GET_MBDN_DONE:
+ //Resetting the voice mail number and voice mail tag to null
+ //as these should be updated from the data read from EF_MBDN.
+ //If they are not reset, incase of invalid data/exception these
+ //variables are retaining their previous values and are
+ //causing invalid voice mailbox info display to user.
+ voiceMailNum = null;
+ voiceMailTag = null;
isRecordLoadResponse = true;
ar = (AsyncResult)msg.obj;
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
index 41e527c..b642541 100644..100755
--- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -53,6 +53,7 @@ public class UsimPhoneBookManager extends Handler implements IccConstants {
private ArrayList<byte[]> mIapFileRecord;
private ArrayList<byte[]> mEmailFileRecord;
private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
+ private boolean mRefreshCache = false;
private static final int EVENT_PBR_LOAD_DONE = 1;
private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
@@ -91,11 +92,19 @@ public class UsimPhoneBookManager extends Handler implements IccConstants {
mEmailFileRecord = null;
mPbrFile = null;
mIsPbrPresent = true;
+ mRefreshCache = false;
}
public ArrayList<AdnRecord> loadEfFilesFromUsim() {
synchronized (mLock) {
- if (!mPhoneBookRecords.isEmpty()) return mPhoneBookRecords;
+ if (!mPhoneBookRecords.isEmpty()) {
+ if (mRefreshCache) {
+ mRefreshCache = false;
+ refreshCache();
+ }
+ return mPhoneBookRecords;
+ }
+
if (!mIsPbrPresent) return null;
// Check if the PBR file is present in the cache, if not read it
@@ -116,6 +125,20 @@ public class UsimPhoneBookManager extends Handler implements IccConstants {
return mPhoneBookRecords;
}
+ private void refreshCache() {
+ if (mPbrFile == null) return;
+ mPhoneBookRecords.clear();
+
+ int numRecs = mPbrFile.mFileIds.size();
+ for (int i = 0; i < numRecs; i++) {
+ readAdnFileAndWait(i);
+ }
+ }
+
+ public void invalidateCache() {
+ mRefreshCache = true;
+ }
+
private void readPbrFileAndWait() {
mPhone.getIccFileHandler().loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
try {
diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml
index f02673c..8331f0c 100644
--- a/tests/CoreTests/android/AndroidManifest.xml
+++ b/tests/CoreTests/android/AndroidManifest.xml
@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- location test permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
diff --git a/tests/CoreTests/android/core/HttpHeaderTest.java b/tests/CoreTests/android/core/HttpHeaderTest.java
new file mode 100644
index 0000000..a5d4857
--- /dev/null
+++ b/tests/CoreTests/android/core/HttpHeaderTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.core;
+
+import android.test.AndroidTestCase;
+import org.apache.http.util.CharArrayBuffer;
+
+import android.net.http.Headers;
+
+public class HttpHeaderTest extends AndroidTestCase {
+
+ static final String LAST_MODIFIED = "Last-Modified: Fri, 18 Jun 2010 09:56:47 GMT";
+ static final String CACHE_CONTROL_MAX_AGE = "Cache-Control:max-age=15";
+ static final String CACHE_CONTROL_PRIVATE = "Cache-Control: private";
+
+ /**
+ * Tests that cache control header supports multiple instances of the header,
+ * according to HTTP specification.
+ *
+ * The HTTP specification states the following about the fields:
+ * Multiple message-header fields with the same field-name MAY be present
+ * in a message if and only if the entire field-value for that header field
+ * is defined as a comma-separated list [i.e., #(values)]. It MUST be
+ * possible to combine the multiple header fields into one "field-name:
+ * field-value" pair, without changing the semantics of the message, by
+ * appending each subsequent field-value to the first, each separated by a
+ * comma. The order in which header fields with the same field-name are
+ * received is therefore significant to the interpretation of the combined
+ * field value, and thus a proxy MUST NOT change the order of these field
+ * values when a message is forwarded.
+ */
+ public void testCacheControl() throws Exception {
+ Headers h = new Headers();
+ CharArrayBuffer buffer = new CharArrayBuffer(64);
+
+ buffer.append(CACHE_CONTROL_MAX_AGE);
+ h.parseHeader(buffer);
+
+ buffer.clear();
+ buffer.append(LAST_MODIFIED);
+ h.parseHeader(buffer);
+ assertEquals("max-age=15", h.getCacheControl());
+
+ buffer.clear();
+ buffer.append(CACHE_CONTROL_PRIVATE);
+ h.parseHeader(buffer);
+ assertEquals("max-age=15,private", h.getCacheControl());
+ }
+}
diff --git a/tests/CoreTests/android/core/ProxyTest.java b/tests/CoreTests/android/core/ProxyTest.java
new file mode 100644
index 0000000..12acfe8
--- /dev/null
+++ b/tests/CoreTests/android/core/ProxyTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import org.apache.http.HttpHost;
+
+import android.content.Context;
+import android.net.Proxy;
+import android.test.AndroidTestCase;
+
+/**
+ * Proxy tests
+ */
+public class ProxyTest extends AndroidTestCase {
+ private Context mContext;
+ private HttpHost mHttpHost;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mContext = getContext();
+ mHttpHost = null;
+ String proxyHost = Proxy.getHost(mContext);
+ int proxyPort = Proxy.getPort(mContext);
+ if (proxyHost != null) {
+ mHttpHost = new HttpHost(proxyHost, proxyPort, "http");
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Bad url parameter should not cause any exception.
+ */
+ public void testProxyGetPreferredHttpHost_UrlBad() throws Exception {
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, null));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, ""));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad:"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad:\\"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad://#"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "://#"));
+ }
+
+ /**
+ * Proxy (if available) should be returned when url parameter is not localhost.
+ */
+ public void testProxyGetPreferredHttpHost_UrlNotlLocalhost() throws Exception {
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://example.com"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://example.com/"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://192.168.0.1/"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "file:///foo/bar"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "rtsp://example.com"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "rtsp://example.com/"));
+ assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "javascript:alert(1)"));
+ }
+
+ /**
+ * No proxy should be returned when url parameter is localhost.
+ */
+ public void testProxyGetPreferredHttpHost_UrlLocalhost() throws Exception {
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost/"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost/hej.html"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1/"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1/hej.html"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1:80/"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1:8080/"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "rtsp://127.0.0.1/"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "rtsp://localhost/"));
+ assertNull(Proxy.getPreferredHttpHost(mContext, "https://localhost/"));
+ }
+}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index a2f085a..a84492d 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -12,6 +12,8 @@
#include <utils/ResourceTypes.h>
#include <stdarg.h>
+#include <set>
+
#define NOISY(x) //x
status_t compileXmlFile(const sp<AaptAssets>& assets,
@@ -2516,6 +2518,34 @@ ResourceFilter::match(const ResTable_config& config)
return true;
}
+class entry_sort_t {
+public:
+ sp<ResourceTable::Package> p;
+ sp<ResourceTable::Type> t;
+ sp<ResourceTable::ConfigList> c;
+ ResourceTable::ConfigDescription config;
+ sp<ResourceTable::Entry> e;
+
+ entry_sort_t() { }
+ entry_sort_t(
+ sp<ResourceTable::Package> p,
+ sp<ResourceTable::Type> t,
+ sp<ResourceTable::ConfigList> c,
+ const ResourceTable::ConfigDescription &config,
+ sp<ResourceTable::Entry> e)
+ : p(p), t(t), c(c), config(config), e(e) { }
+
+ bool operator < (const entry_sort_t &o) const {
+ int cmp;
+ if ((cmp = compare_type(config, o.config))) return cmp < 0;
+ if ((cmp = compare_type(t, o.t))) return cmp < 0;
+ if ((cmp = compare_type(e, o.e))) return cmp < 0;
+ if ((cmp = compare_type(c, o.c))) return cmp < 0;
+ if ((cmp = compare_type(p, o.p))) return cmp < 0;
+ return false;
+ }
+};
+
status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
{
ResourceFilter filter;
@@ -2528,6 +2558,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
size_t pi;
bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO);
+ std::set< entry_sort_t > sortedEntries;
// Iterate through all data, collecting all values (strings,
// references, etc).
@@ -2568,10 +2599,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
continue;
}
e->setNameIndex(keyStrings.add(e->getName(), true));
- status_t err = e->prepareFlatten(&valueStrings, this);
- if (err != NO_ERROR) {
- return err;
- }
+ sortedEntries.insert(entry_sort_t(p, t, c, config, e));
}
}
}
@@ -2580,6 +2608,16 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
p->setKeyStrings(keyStrings.createStringBlock());
}
+ for (std::set< entry_sort_t >::iterator ei=sortedEntries.begin(); ei!=sortedEntries.end(); ++ei) {
+ sp<Entry> e = ei->e;
+ status_t err = e->prepareFlatten(&valueStrings, this);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+
+ sortedEntries.clear();
+
ssize_t strAmt = 0;
// Now build the array of package chunks.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
index d5d315e..d75ec79 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
@@ -49,6 +49,8 @@ import javax.microedition.khronos.opengles.GL;
*/
public class Canvas extends _Original_Canvas {
+ private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
+ private static final char LAST_RIGHT_TO_LEFT = '\u07b1';
private BufferedImage mBufferedImage;
private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
private final ILayoutLog mLogger;
@@ -644,11 +646,8 @@ public class Canvas extends _Original_Canvas {
getGraphics2d().scale(sx, sy);
}
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
+
+ public void drawText(char[] text, int index, int count, float x, float y, Paint paint, boolean bidi) {
// WARNING: the logic in this method is similar to Paint.measureText.
// Any change to this method should be reflected in Paint.measureText
Graphics2D g = getGraphics2d();
@@ -681,21 +680,29 @@ public class Canvas extends _Original_Canvas {
FontInfo mainFont = fonts.get(0);
int i = index;
int lastIndex = index + count;
+ char[] bidiText;
+ if (bidi) {
+ bidiText=bidiProcess(text,index,count);
+ i=0;
+ lastIndex=count;
+ } else {
+ bidiText=text;
+ }
while (i < lastIndex) {
// always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ int upTo = mainFont.mFont.canDisplayUpTo(bidiText, i, lastIndex);
if (upTo == -1) {
// draw all the rest and exit.
g.setFont(mainFont.mFont);
- g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
+ g.drawChars(bidiText, i, lastIndex - i, (int)x, (int)y);
return;
} else if (upTo > 0) {
// draw what's possible
g.setFont(mainFont.mFont);
- g.drawChars(text, i, upTo - i, (int)x, (int)y);
+ g.drawChars(bidiText, i, upTo - i, (int)x, (int)y);
// compute the width that was drawn to increase x
- x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+ x += mainFont.mMetrics.charsWidth(bidiText, i, upTo - i);
// move index to the first non displayed char.
i = upTo;
@@ -715,15 +722,15 @@ public class Canvas extends _Original_Canvas {
// need to check that the font can display the character. We test
// differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ int charCount = Character.isHighSurrogate(bidiText[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(bidiText, i, i + charCount);
if (upTo == -1) {
// draw that char
g.setFont(fontInfo.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
+ g.drawChars(bidiText, i, charCount, (int)x, (int)y);
// update x
- x += fontInfo.mMetrics.charsWidth(text, i, charCount);
+ x += fontInfo.mMetrics.charsWidth(bidiText, i, charCount);
// update the index in the text, and move on
i += charCount;
@@ -736,13 +743,13 @@ public class Canvas extends _Original_Canvas {
// in case no font can display the char, display it with the main font.
// (it'll put a square probably)
if (foundFont == false) {
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ int charCount = Character.isHighSurrogate(bidiText[i]) ? 2 : 1;
g.setFont(mainFont.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
+ g.drawChars(bidiText, i, charCount, (int)x, (int)y);
// measure it to advance x
- x += mainFont.mMetrics.charsWidth(text, i, charCount);
+ x += mainFont.mMetrics.charsWidth(bidiText, i, charCount);
// and move to the next chars.
i += charCount;
@@ -755,6 +762,13 @@ public class Canvas extends _Original_Canvas {
}
/* (non-Javadoc)
+ * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
+ */
+ @Override
+ public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
+ drawText(text, index, count, x, y, paint, true);
+ }
+ /* (non-Javadoc)
* @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
*/
@Override
@@ -1140,7 +1154,10 @@ public class Canvas extends _Original_Canvas {
public void drawTextOnPath(char[] text, int index, int count, Path path, float offset,
float offset2, Paint paint) {
// TODO Auto-generated method stub
- super.drawTextOnPath(text, index, count, path, offset, offset2, paint);
+ int i = 0;
+ char[] bidiText;
+ bidiText=bidiProcess(text,index,count);
+ super.drawTextOnPath(bidiText, i, count, path, offset, offset2, paint);
}
/* (non-Javadoc)
@@ -1149,7 +1166,10 @@ public class Canvas extends _Original_Canvas {
@Override
public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) {
// TODO Auto-generated method stub
- super.drawTextOnPath(text, path, offset, offset2, paint);
+ int i = 0;
+ String bidiText;
+ bidiText=new String(bidiProcess(text.toCharArray(),0,text.length()));
+ super.drawTextOnPath(bidiText, path, offset, offset2, paint);
}
/* (non-Javadoc)
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
index 619ab30..d13b5fe 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint.java
@@ -283,6 +283,8 @@ public class Paint extends _Original_Paint {
mStyle = src.mStyle;
mFlags = src.mFlags;
+ updateFontObject();
+
super.set(src);
}
}
diff --git a/vpn/java/android/net/vpn/OpenvpnProfile.java b/vpn/java/android/net/vpn/OpenvpnProfile.java
new file mode 100644
index 0000000..f1fd2f6
--- /dev/null
+++ b/vpn/java/android/net/vpn/OpenvpnProfile.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 android.net.vpn;
+
+import android.os.Parcel;
+
+/**
+ * The profile for Openvpn type of VPN.
+ * {@hide}
+ */
+public class OpenvpnProfile extends VpnProfile {
+ private static final long serialVersionUID = 1L;
+
+ private static final String PROTO_UDP = "udp";
+
+ private static final String PROTO_TCP = "tcp";
+
+ private static final String DEVICE_TUN = "tun";
+
+ private static final String DEVICE_TAP = "tap";
+
+ // Standard Settings
+ private boolean mUserAuth = false;
+
+ private String mCA;
+
+ private String mCert;
+
+ // Advanced Settings
+ private int mPort = 1194;
+
+ private String mProto = PROTO_UDP;
+
+ private boolean mUseCompLzo = false;
+
+ private boolean mSupplyAddr = false;
+
+ private boolean mRedirectGateway = false;
+
+ private String mLocalAddr;
+
+ private String mRemoteAddr;
+
+ private String mDevice = DEVICE_TUN;
+
+ private String mCipher;
+
+ private int mKeySize;
+
+ private String mExtra;
+
+ @Override
+ public VpnType getType() {
+ return VpnType.OPENVPN;
+ }
+
+ public void setPort(String port) {
+ try {
+ mPort = Integer.parseInt(port);
+ } catch (NumberFormatException e) {
+ // no update
+ }
+ }
+
+ public String getPort() {
+ return Integer.toString(mPort);
+ }
+
+ public String getProto() {
+ return mProto;
+ }
+
+ public CharSequence[] getProtoList() {
+ String[] s = new String[2];
+ s[0] = PROTO_UDP;
+ s[1] = PROTO_TCP;
+ return s;
+ }
+
+ public void setProto(String p) {
+ if (p.contains(PROTO_TCP))
+ mProto = PROTO_TCP;
+ else if (p.contains(PROTO_UDP))
+ mProto = PROTO_UDP;
+ }
+
+ public String getDevice() {
+ return mDevice;
+ }
+
+ public CharSequence[] getDeviceList() {
+ String[] s = new String[2];
+ s[0] = DEVICE_TUN;
+ s[1] = DEVICE_TAP;
+ return s;
+ }
+
+ public void setDevice(String p) {
+ if (p.contains(DEVICE_TAP))
+ mDevice = DEVICE_TAP;
+ else if (p.contains(DEVICE_TUN))
+ mDevice = DEVICE_TUN;
+ }
+
+ public boolean getUserAuth() {
+ return mUserAuth;
+ }
+
+ public void setUserAuth(boolean auth) {
+ mUserAuth = auth;
+ }
+
+ public String getCAName() {
+ return mCA;
+ }
+
+ public void setCAName(String name) {
+ mCA = name;
+ }
+
+ public String getCertName() {
+ return mCert;
+ }
+
+ public void setCertName(String name) {
+ mCert = name;
+ }
+
+ public void setUseCompLzo(boolean b) {
+ mUseCompLzo = b;
+ }
+
+ public boolean getUseCompLzo() {
+ return mUseCompLzo;
+ }
+
+ public void setRedirectGateway(boolean b) {
+ mRedirectGateway = b;
+ }
+
+ public boolean getRedirectGateway() {
+ return mRedirectGateway;
+ }
+
+ public void setSupplyAddr(boolean b) {
+ mSupplyAddr = b;
+ }
+
+ public boolean getSupplyAddr() {
+ return mSupplyAddr;
+ }
+
+ public void setLocalAddr(String addr) {
+ mLocalAddr = addr;
+ }
+
+ public String getLocalAddr() {
+ return mLocalAddr;
+ }
+
+ public void setRemoteAddr(String addr) {
+ mRemoteAddr = addr;
+ }
+
+ public String getRemoteAddr() {
+ return mRemoteAddr;
+ }
+
+ public void setCipher(String cipher) {
+ mCipher = cipher;
+ }
+
+ public String getCipher() {
+ return mCipher;
+ }
+
+ public void setKeySize(String keysize) {
+ try {
+ if (keysize.equals("0"))
+ mKeySize = 0;
+ else
+ mKeySize = Integer.parseInt(keysize);
+ } catch (NumberFormatException e) {
+ // no update
+ }
+ }
+
+ public String getKeySize() {
+ return Integer.toString(mKeySize);
+ }
+
+ public void setExtra(String extra) {
+ mExtra = extra;
+ }
+
+ public String getExtra() {
+ return mExtra;
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ super.readFromParcel(in);
+ mPort = in.readInt();
+ mProto = in.readString();
+ mUserAuth = in.readInt() == 1;
+ mCA = in.readString();
+ mCert = in.readString();
+ mUseCompLzo = in.readInt() == 1;
+ mRedirectGateway = in.readInt() == 1;
+ mSupplyAddr = in.readInt() == 1;
+ mLocalAddr = in.readString();
+ mRemoteAddr = in.readString();
+ mDevice = in.readString();
+ mCipher = in.readString();
+ mKeySize = in.readInt();
+ mExtra = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ super.writeToParcel(parcel, flags);
+ parcel.writeInt(mPort);
+ parcel.writeString(mProto);
+ parcel.writeInt(mUserAuth ? 1 : 0);
+ parcel.writeString(mCA);
+ parcel.writeString(mCert);
+ parcel.writeInt(mUseCompLzo ? 1 : 0);
+ parcel.writeInt(mRedirectGateway ? 1 : 0);
+ parcel.writeInt(mSupplyAddr ? 1 : 0);
+ parcel.writeString(mLocalAddr);
+ parcel.writeString(mRemoteAddr);
+ parcel.writeString(mDevice);
+ parcel.writeString(mCipher);
+ parcel.writeInt(mKeySize);
+ parcel.writeString(mExtra);
+ }
+}
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index ce522c8..c588076 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -69,7 +69,7 @@ public class VpnManager {
/** Error code to indicate a successful connection. */
public static final int VPN_ERROR_NO_ERROR = 0;
- public static final String PROFILES_PATH = "/misc/vpn/profiles";
+ public static final String PROFILES_PATH = "/data/misc/vpn/profiles";
private static final String PACKAGE_PREFIX =
VpnManager.class.getPackage().getName() + ".";
diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java
index 356f8b1..2157067 100644
--- a/vpn/java/android/net/vpn/VpnType.java
+++ b/vpn/java/android/net/vpn/VpnType.java
@@ -28,7 +28,8 @@ public enum VpnType {
L2TP_IPSEC_PSK("L2TP/IPSec PSK", R.string.l2tp_ipsec_psk_vpn_description,
L2tpIpsecPskProfile.class),
L2TP_IPSEC("L2TP/IPSec CRT", R.string.l2tp_ipsec_crt_vpn_description,
- L2tpIpsecProfile.class);
+ L2tpIpsecProfile.class),
+ OPENVPN("OpenVPN", R.string.openvpn_vpn_description, OpenvpnProfile.class);
private String mDisplayName;
private int mDescriptionId;
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index f98cd28..f4afc36 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -16,8 +16,6 @@
package android.net.wifi;
-import android.net.DhcpInfo;
-
/**
* Native calls for sending requests to the supplicant daemon, and for
* receiving asynchronous events. All methods of the form "xxxxCommand()"
@@ -143,10 +141,6 @@ public class WifiNative {
public native static boolean clearBlacklistCommand();
- public native static boolean doDhcpRequest(DhcpInfo results);
-
- public native static String getDhcpError();
-
/**
* Wait for the supplicant to send an event, returning the event string.
* @return the event string sent by the supplicant.
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 3813015..542a0ac 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -69,7 +69,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class WifiStateTracker extends NetworkStateTracker {
private static final boolean LOCAL_LOGD = Config.LOGD || false;
-
+
private static final String TAG = "WifiStateTracker";
// Event log tags (must be in sync with event-log-tags)
@@ -216,12 +216,12 @@ public class WifiStateTracker extends NetworkStateTracker {
private boolean mUseStaticIp = false;
private int mReconnectCount;
- // used to store the (non-persisted) num determined during device boot
+ // used to store the (non-persisted) num determined during device boot
// (from mcc or other phone info) before the driver is started.
private int mNumAllowedChannels = 0;
// Variables relating to the 'available networks' notification
-
+
/**
* The icon to show in the 'available networks' notification. This will also
* be the ID of the Notification given to the NotificationManager.
@@ -273,7 +273,7 @@ public class WifiStateTracker extends NetworkStateTracker {
* Observes the static IP address settings.
*/
private SettingsObserver mSettingsObserver;
-
+
private boolean mIsScanModeActive;
private boolean mEnableRssiPolling;
@@ -313,8 +313,6 @@ public class WifiStateTracker extends NetworkStateTracker {
private String mInterfaceName;
private static String LS = System.getProperty("line.separator");
- private static String[] sDnsPropNames;
-
/**
* A structure for supplying information about a supplicant state
* change in the STATE_CHANGE event message that comes from the
@@ -350,7 +348,7 @@ public class WifiStateTracker extends NetworkStateTracker {
public WifiStateTracker(Context context, Handler target) {
super(context, target, ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
-
+
mWifiInfo = new WifiInfo();
mWifiMonitor = new WifiMonitor(this);
mHaveIpAddress = false;
@@ -363,7 +361,7 @@ public class WifiStateTracker extends NetworkStateTracker {
mRunState = RUN_STATE_STARTING;
// Setting is in seconds
- NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
+ NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
mNotificationEnabledSettingObserver.register();
@@ -371,9 +369,9 @@ public class WifiStateTracker extends NetworkStateTracker {
mSettingsObserver = new SettingsObserver(new Handler());
mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0");
- sDnsPropNames = new String[] {
- "dhcp." + mInterfaceName + ".dns1",
- "dhcp." + mInterfaceName + ".dns2"
+ mDnsPropNames = new String[] {
+ "net." + mInterfaceName + ".dns1",
+ "net." + mInterfaceName + ".dns2"
};
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
@@ -418,15 +416,6 @@ public class WifiStateTracker extends NetworkStateTracker {
}
/**
- * Return the IP addresses of the DNS servers available for the WLAN
- * network interface.
- * @return a list of DNS addresses, with no holes.
- */
- public String[] getNameServers() {
- return getNameServerList(sDnsPropNames);
- }
-
- /**
* Return the name of our WLAN network interface.
* @return the name of our interface.
*/
@@ -994,10 +983,10 @@ public class WifiStateTracker extends NetworkStateTracker {
// Wi-Fi network state changed:
// [31- 6] Reserved for future use
- // [ 5- 0] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
+ // [ 5- 0] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
eventLogParam = (result.state.ordinal() & 0x3f);
EventLog.writeEvent(EVENTLOG_NETWORK_STATE_CHANGED, eventLogParam);
-
+
if (LOCAL_LOGD) Log.v(TAG, "New network state is " + result.state);
/*
* If we're in scan-only mode, don't advance the state machine, and
@@ -1085,7 +1074,7 @@ public class WifiStateTracker extends NetworkStateTracker {
checkPollTimer();
}
break;
-
+
case EVENT_DEFERRED_DISCONNECT:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
handleDisconnectedState(DetailedState.DISCONNECTED, true);
@@ -1137,7 +1126,7 @@ public class WifiStateTracker extends NetworkStateTracker {
if (LOCAL_LOGD) Log.v(TAG, "IP configuration: " + mDhcpInfo);
// Wi-Fi interface configuration state changed:
// [31- 1] Reserved for future use
- // [ 0- 0] Interface configuration succeeded (1) or failed (0)
+ // [ 0- 0] Interface configuration succeeded (1) or failed (0)
EventLog.writeEvent(EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED, 1);
// We've connected successfully, so allow the notification again in the future
@@ -1357,7 +1346,7 @@ public class WifiStateTracker extends NetworkStateTracker {
int netId = -1;
String[] lines = reply.split("\n");
for (String line : lines) {
- String[] prop = line.split(" *= *");
+ String[] prop = line.split(" *= *", 2);
if (prop.length < 2)
continue;
String name = prop[0];
@@ -2094,7 +2083,7 @@ public class WifiStateTracker extends NetworkStateTracker {
numOpenNetworks++;
}
}
-
+
if (numOpenNetworks > 0) {
if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
/*
@@ -2110,7 +2099,7 @@ public class WifiStateTracker extends NetworkStateTracker {
}
}
}
-
+
// No open networks in range, remove the notification
setNotificationVisible(false, 0, false, 0);
}
@@ -2125,13 +2114,13 @@ public class WifiStateTracker extends NetworkStateTracker {
* visible or invisible.
*/
public void setNotificationVisible(boolean visible, int numNetworks, boolean force, int delay) {
-
+
// Since we use auto cancel on the notification, when the
// mNetworksAvailableNotificationShown is true, the notification may
// have actually been canceled. However, when it is false we know
// for sure that it is not being shown (it will not be shown any other
// place than here)
-
+
// If it should be hidden and it is already hidden, then noop
if (!visible && !mNotificationShown && !force) {
return;
@@ -2139,12 +2128,12 @@ public class WifiStateTracker extends NetworkStateTracker {
Message message;
if (visible) {
-
+
// Not enough time has passed to show the notification again
if (System.currentTimeMillis() < mNotificationRepeatTime) {
return;
}
-
+
if (mNotification == null) {
// Cache the Notification mainly so we can remove the
// EVENT_NOTIFICATION_CHANGED message with this Notification from
@@ -2163,22 +2152,22 @@ public class WifiStateTracker extends NetworkStateTracker {
com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
mNotification.tickerText = title;
mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
-
+
mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
message = mTarget.obtainMessage(EVENT_NOTIFICATION_CHANGED, 1,
ICON_NETWORKS_AVAILABLE, mNotification);
-
+
} else {
// Remove any pending messages to show the notification
mTarget.removeMessages(EVENT_NOTIFICATION_CHANGED, mNotification);
-
+
message = mTarget.obtainMessage(EVENT_NOTIFICATION_CHANGED, 0, ICON_NETWORKS_AVAILABLE);
}
mTarget.sendMessageDelayed(message, delay);
-
+
mNotificationShown = visible;
}
@@ -2193,7 +2182,7 @@ public class WifiStateTracker extends NetworkStateTracker {
mNotificationRepeatTime = 0;
mNumScansSinceNetworkStateChange = 0;
}
-
+
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
@@ -2217,7 +2206,7 @@ public class WifiStateTracker extends NetworkStateTracker {
private class DhcpHandler extends Handler {
private Handler mTarget;
-
+
/**
* Whether to skip the DHCP result callback to the target. For example,
* this could be set if the network we were requesting an IP for has
@@ -2237,11 +2226,11 @@ public class WifiStateTracker extends NetworkStateTracker {
* in an error state and we will not disable coexistence.
*/
private BluetoothHeadset mBluetoothHeadset;
-
+
public DhcpHandler(Looper looper, Handler target) {
super(looper);
mTarget = target;
-
+
mBluetoothHeadset = new BluetoothHeadset(mContext, null);
}
@@ -2250,7 +2239,7 @@ public class WifiStateTracker extends NetworkStateTracker {
switch (msg.what) {
case EVENT_DHCP_START:
-
+
boolean modifiedBluetoothCoexistenceMode = false;
if (shouldDisableCoexistenceMode()) {
/*
@@ -2319,7 +2308,7 @@ public class WifiStateTracker extends NetworkStateTracker {
* headset/handsfree state is disconnected. This means if it is in an
* error state, we will NOT disable coexistence mode to err on the side
* of safety.
- *
+ *
* @return Whether to disable coexistence mode.
*/
private boolean shouldDisableCoexistenceMode() {
@@ -2327,7 +2316,7 @@ public class WifiStateTracker extends NetworkStateTracker {
return state == BluetoothHeadset.STATE_DISCONNECTED;
}
}
-
+
private void checkUseStaticIp() {
mUseStaticIp = false;
final ContentResolver cr = mContext.getContentResolver();