summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk8
-rw-r--r--api/current.xml1382
-rw-r--r--cmds/stagefright/stagefright.cpp6
-rw-r--r--core/java/android/app/ContextImpl.java21
-rw-r--r--core/java/android/app/DownloadManager.java (renamed from core/java/android/net/DownloadManager.java)4
-rw-r--r--core/java/android/content/Context.java16
-rw-r--r--core/java/android/content/res/ObbInfo.java9
-rw-r--r--core/java/android/content/res/ObbScanner.java34
-rw-r--r--core/java/android/os/storage/OnObbStateChangeListener.java31
-rw-r--r--core/java/android/os/storage/StorageManager.java167
-rw-r--r--core/java/android/provider/Settings.java94
-rw-r--r--core/java/android/webkit/WebView.java2
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl34
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl32
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl41
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl32
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl61
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl38
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl32
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl33
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/LlcpConnectionlessSocket.java148
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/LlcpException.java42
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/LlcpPacket.aidl19
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/LlcpPacket.java119
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/LlcpServiceSocket.java180
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/LlcpSocket.java344
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NdefMessage.aidl19
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NdefMessage.java160
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NdefRecord.aidl19
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NdefRecord.java293
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NdefTag.java126
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NfcException.java42
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NfcManager.java656
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/NfcTag.java250
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/P2pDevice.java89
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/P2pInitiator.java115
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/P2pTarget.java183
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/ErrorCodes.java91
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpConnectionlessSocket.java68
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpServiceSocket.java82
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpSocket.java93
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/NativeNdefTag.java36
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcManager.java325
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcTag.java62
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/internal/NativeP2pDevice.java75
-rw-r--r--core/java/com/trustedlogic/trustednfc/android/package.html473
-rw-r--r--core/jni/Android.mk8
-rw-r--r--core/jni/AndroidRuntime.cpp24
-rw-r--r--core/jni/android_content_res_ObbScanner.cpp23
-rw-r--r--core/res/AndroidManifest.xml36
-rw-r--r--core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.pngbin7968 -> 13950 bytes
-rw-r--r--core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.pngbin6849 -> 11338 bytes
-rw-r--r--[-rwxr-xr-x]core/res/res/drawable-hdpi/stat_notify_car_mode.pngbin1330 -> 624 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_email_generic.pngbin409 -> 337 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/drawable-hdpi/stat_notify_error.pngbin1057 -> 1456 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_gmail.pngbin388 -> 345 bytes
-rw-r--r--[-rwxr-xr-x]core/res/res/drawable-hdpi/stat_notify_missed_call.pngbin1926 -> 1166 bytes
-rwxr-xr-xcore/res/res/drawable-hdpi/stat_notify_more.pngbin1102 -> 1295 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/drawable-hdpi/stat_notify_sdcard_usb.pngbin1270 -> 1305 bytes
-rwxr-xr-xcore/res/res/drawable-hdpi/stat_notify_sync_error.pngbin1714 -> 1806 bytes
-rw-r--r--[-rwxr-xr-x]core/res/res/drawable-hdpi/stat_notify_wifi_in_range.pngbin1727 -> 1290 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/values/strings.xml127
-rw-r--r--core/tests/coretests/src/android/app/DownloadManagerBaseTest.java (renamed from core/tests/coretests/src/android/net/DownloadManagerBaseTest.java)8
-rw-r--r--core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java (renamed from core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java)12
-rw-r--r--core/tests/coretests/src/android/app/DownloadManagerStressTest.java (renamed from core/tests/coretests/src/android/net/DownloadManagerStressTest.java)7
-rw-r--r--core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java8
-rw-r--r--include/media/stagefright/AudioPlayer.h6
-rw-r--r--include/media/stagefright/MPEG2TSWriter.h72
-rw-r--r--include/media/stagefright/MetaData.h2
-rw-r--r--include/storage/IMountService.h3
-rw-r--r--libs/storage/IMountService.cpp6
-rw-r--r--libs/ui/InputDispatcher.cpp11
-rw-r--r--location/Android.mk19
-rw-r--r--location/lib/Android.mk45
-rw-r--r--location/lib/com.android.location.provider.xml20
-rw-r--r--location/lib/java/com/android/location/provider/GeocodeProvider.java (renamed from location/java/android/location/provider/GeocodeProvider.java)3
-rw-r--r--location/lib/java/com/android/location/provider/LocationProvider.java (renamed from location/java/android/location/provider/LocationProvider.java)3
-rw-r--r--media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp334
-rw-r--r--media/libeffects/lvm/wrapper/Bundle/EffectBundle.h3
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp6
-rw-r--r--media/libstagefright/Android.mk1
-rw-r--r--media/libstagefright/AudioPlayer.cpp22
-rw-r--r--media/libstagefright/AwesomePlayer.cpp16
-rw-r--r--media/libstagefright/MPEG2TSWriter.cpp758
-rw-r--r--media/libstagefright/OggExtractor.cpp77
-rw-r--r--media/libstagefright/codecs/aacdec/AACDecoder.cpp4
-rw-r--r--media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h32
-rw-r--r--media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h21
-rw-r--r--media/libstagefright/codecs/amrnb/enc/src/gsmamr_enc.h21
-rw-r--r--media/libstagefright/codecs/mp3dec/MP3Decoder.cpp4
-rw-r--r--media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp18
-rw-r--r--media/libstagefright/include/AwesomePlayer.h3
-rw-r--r--media/libstagefright/include/VorbisDecoder.h1
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp48
-rw-r--r--media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp55
-rw-r--r--native/android/Android.mk1
-rw-r--r--native/android/obb.cpp54
-rw-r--r--native/android/storage_manager.cpp31
-rw-r--r--native/include/android/obb.h63
-rw-r--r--native/include/android/storage_manager.h15
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java7
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.pngbin1021 -> 210 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.pngbin4468 -> 1331 bytes
-rw-r--r--[-rwxr-xr-x]packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.pngbin4491 -> 1359 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.pngbin809 -> 199 bytes
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java2
-rw-r--r--services/audioflinger/AudioFlinger.cpp40
-rw-r--r--services/java/com/android/server/MountService.java90
-rw-r--r--services/java/com/android/server/PowerManagerService.java2
-rw-r--r--services/java/com/android/server/SystemServer.java16
-rw-r--r--services/java/com/android/server/WifiService.java4
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java76
-rw-r--r--services/java/com/trustedlogic/trustednfc/android/server/NfcService.java2111
-rw-r--r--telephony/java/com/android/internal/telephony/Connection.java1
-rwxr-xr-xtelephony/java/com/android/internal/telephony/sip/SipPhone.java43
-rw-r--r--tools/layoutlib/Android.mk12
-rw-r--r--voip/java/android/net/rtp/AudioCodec.java2
-rw-r--r--voip/java/com/android/server/sip/SipSessionGroup.java13
-rw-r--r--voip/jni/rtp/AmrCodec.cpp97
-rw-r--r--voip/jni/rtp/Android.mk19
-rw-r--r--voip/jni/rtp/AudioCodec.cpp126
-rw-r--r--voip/jni/rtp/AudioGroup.cpp307
-rw-r--r--voip/jni/rtp/G711Codec.cpp138
-rw-r--r--voip/jni/rtp/GsmCodec.cpp74
126 files changed, 10056 insertions, 1344 deletions
diff --git a/Android.mk b/Android.mk
index 566b36f..6dc39eb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -159,6 +159,14 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/view/IInputMethodClient.aidl \
core/java/com/android/internal/view/IInputMethodManager.aidl \
core/java/com/android/internal/view/IInputMethodSession.aidl \
+ core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl \
+ core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl \
+ core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl \
+ core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl \
+ core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl \
+ core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl \
+ core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl \
+ core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
diff --git a/api/current.xml b/api/current.xml
index 876fe00..a37a533 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -24488,6 +24488,623 @@
</parameter>
</method>
</class>
+<class name="DownloadManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="enqueue"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="android.app.DownloadManager.Request">
+</parameter>
+</method>
+<method name="openDownloadedFile"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="long">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+</method>
+<method name="query"
+ return="android.database.Cursor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="query" type="android.app.DownloadManager.Query">
+</parameter>
+</method>
+<method name="remove"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="long">
+</parameter>
+</method>
+<field name="ACTION_DOWNLOAD_COMPLETE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.DOWNLOAD_COMPLETE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_NOTIFICATION_CLICKED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_VIEW_DOWNLOADS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.VIEW_DOWNLOADS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_BYTES_DOWNLOADED_SO_FAR"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;bytes_so_far&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_DESCRIPTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;description&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_ERROR_CODE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;error_code&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_LAST_MODIFIED_TIMESTAMP"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;last_modified_timestamp&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_LOCAL_URI"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;local_uri&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_MEDIA_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;media_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_STATUS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;status&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_TITLE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;title&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_TOTAL_SIZE_BYTES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;total_size&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COLUMN_URI"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;uri&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CANNOT_RESUME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1008"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_DEVICE_NOT_FOUND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1007"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_FILE_ALREADY_EXISTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1009"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_FILE_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1001"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_HTTP_DATA_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1004"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_INSUFFICIENT_SPACE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1006"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_TOO_MANY_REDIRECTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1005"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_UNHANDLED_HTTP_CODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1002"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOWNLOAD_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;extra_download_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_PAUSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_PENDING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_RUNNING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_SUCCESSFUL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="DownloadManager.Query"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DownloadManager.Query"
+ type="android.app.DownloadManager.Query"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="setFilterById"
+ return="android.app.DownloadManager.Query"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="long">
+</parameter>
+</method>
+<method name="setFilterByStatus"
+ return="android.app.DownloadManager.Query"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+</class>
+<class name="DownloadManager.Request"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DownloadManager.Request"
+ type="android.app.DownloadManager.Request"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</constructor>
+<method name="addRequestHeader"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="header" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
+<method name="setAllowedNetworkTypes"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="setAllowedOverRoaming"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="allowed" type="boolean">
+</parameter>
+</method>
+<method name="setDescription"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="description" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="setDestinationInExternalFilesDir"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="dirType" type="java.lang.String">
+</parameter>
+<parameter name="subPath" type="java.lang.String">
+</parameter>
+</method>
+<method name="setDestinationInExternalPublicDir"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dirType" type="java.lang.String">
+</parameter>
+<parameter name="subPath" type="java.lang.String">
+</parameter>
+</method>
+<method name="setDestinationUri"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="setMimeType"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+<method name="setShowRunningNotification"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="show" type="boolean">
+</parameter>
+</method>
+<method name="setTitle"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="title" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="setVisibleInDownloadsUi"
+ return="android.app.DownloadManager.Request"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="isVisible" type="boolean">
+</parameter>
+</method>
+<field name="NETWORK_MOBILE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NETWORK_WIFI"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="ExpandableListActivity"
extends="android.app.Activity"
abstract="false"
@@ -52002,6 +52619,118 @@
>
</field>
</class>
+<class name="ObbInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="parcelableFlags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OBB_OVERLAY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="flags"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="packageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="version"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="ObbScanner"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getObbInfo"
+ return="android.content.res.ObbInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="filePath" type="java.lang.String">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+</class>
<class name="Resources"
extends="java.lang.Object"
abstract="false"
@@ -95347,623 +96076,6 @@
>
</field>
</class>
-<class name="DownloadManager"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="enqueue"
- return="long"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="request" type="android.net.DownloadManager.Request">
-</parameter>
-</method>
-<method name="openDownloadedFile"
- return="android.os.ParcelFileDescriptor"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="id" type="long">
-</parameter>
-<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
-</exception>
-</method>
-<method name="query"
- return="android.database.Cursor"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="query" type="android.net.DownloadManager.Query">
-</parameter>
-</method>
-<method name="remove"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="id" type="long">
-</parameter>
-</method>
-<field name="ACTION_DOWNLOAD_COMPLETE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.action.DOWNLOAD_COMPLETE&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_NOTIFICATION_CLICKED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_VIEW_DOWNLOADS"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.action.VIEW_DOWNLOADS&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_BYTES_DOWNLOADED_SO_FAR"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;bytes_so_far&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_DESCRIPTION"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;description&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_ERROR_CODE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;error_code&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_ID"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;_id&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_LAST_MODIFIED_TIMESTAMP"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;last_modified_timestamp&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_LOCAL_URI"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;local_uri&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_MEDIA_TYPE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;media_type&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_STATUS"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;status&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_TITLE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;title&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_TOTAL_SIZE_BYTES"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;total_size&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="COLUMN_URI"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;uri&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_CANNOT_RESUME"
- type="int"
- transient="false"
- volatile="false"
- value="1008"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_DEVICE_NOT_FOUND"
- type="int"
- transient="false"
- volatile="false"
- value="1007"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_FILE_ALREADY_EXISTS"
- type="int"
- transient="false"
- volatile="false"
- value="1009"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_FILE_ERROR"
- type="int"
- transient="false"
- volatile="false"
- value="1001"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_HTTP_DATA_ERROR"
- type="int"
- transient="false"
- volatile="false"
- value="1004"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_INSUFFICIENT_SPACE"
- type="int"
- transient="false"
- volatile="false"
- value="1006"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_TOO_MANY_REDIRECTS"
- type="int"
- transient="false"
- volatile="false"
- value="1005"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_UNHANDLED_HTTP_CODE"
- type="int"
- transient="false"
- volatile="false"
- value="1002"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ERROR_UNKNOWN"
- type="int"
- transient="false"
- volatile="false"
- value="1000"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="EXTRA_DOWNLOAD_ID"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;extra_download_id&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATUS_FAILED"
- type="int"
- transient="false"
- volatile="false"
- value="16"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATUS_PAUSED"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATUS_PENDING"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATUS_RUNNING"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATUS_SUCCESSFUL"
- type="int"
- transient="false"
- volatile="false"
- value="8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
-<class name="DownloadManager.Query"
- extends="java.lang.Object"
- abstract="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="DownloadManager.Query"
- type="android.net.DownloadManager.Query"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="setFilterById"
- return="android.net.DownloadManager.Query"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="id" type="long">
-</parameter>
-</method>
-<method name="setFilterByStatus"
- return="android.net.DownloadManager.Query"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="flags" type="int">
-</parameter>
-</method>
-</class>
-<class name="DownloadManager.Request"
- extends="java.lang.Object"
- abstract="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="DownloadManager.Request"
- type="android.net.DownloadManager.Request"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-</constructor>
-<method name="addRequestHeader"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="header" type="java.lang.String">
-</parameter>
-<parameter name="value" type="java.lang.String">
-</parameter>
-</method>
-<method name="setAllowedNetworkTypes"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="setAllowedOverRoaming"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="allowed" type="boolean">
-</parameter>
-</method>
-<method name="setDescription"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="description" type="java.lang.CharSequence">
-</parameter>
-</method>
-<method name="setDestinationInExternalFilesDir"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="dirType" type="java.lang.String">
-</parameter>
-<parameter name="subPath" type="java.lang.String">
-</parameter>
-</method>
-<method name="setDestinationInExternalPublicDir"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="dirType" type="java.lang.String">
-</parameter>
-<parameter name="subPath" type="java.lang.String">
-</parameter>
-</method>
-<method name="setDestinationUri"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="uri" type="android.net.Uri">
-</parameter>
-</method>
-<method name="setMimeType"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="mimeType" type="java.lang.String">
-</parameter>
-</method>
-<method name="setShowRunningNotification"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="show" type="boolean">
-</parameter>
-</method>
-<method name="setTitle"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="title" type="java.lang.CharSequence">
-</parameter>
-</method>
-<method name="setVisibleInDownloadsUi"
- return="android.net.DownloadManager.Request"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="isVisible" type="boolean">
-</parameter>
-</method>
-<field name="NETWORK_MOBILE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="NETWORK_WIFI"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
<class name="LocalServerSocket"
extends="java.lang.Object"
abstract="false"
@@ -129032,6 +129144,38 @@
</package>
<package name="android.os.storage"
>
+<class name="OnObbStateChangeListener"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="OnObbStateChangeListener"
+ type="android.os.storage.OnObbStateChangeListener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onObbStateChange"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="state" type="java.lang.String">
+</parameter>
+</method>
+</class>
<class name="StorageManager"
extends="java.lang.Object"
abstract="false"
@@ -129082,6 +129226,8 @@
</parameter>
<parameter name="key" type="java.lang.String">
</parameter>
+<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
+</parameter>
</method>
<method name="unmountObb"
return="boolean"
@@ -129097,6 +129243,8 @@
</parameter>
<parameter name="force" type="boolean">
</parameter>
+<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
+</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 8b54871..f55b746 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -46,6 +46,7 @@
#include <media/mediametadataretriever.h>
#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
#include <fcntl.h>
@@ -366,8 +367,13 @@ status_t DetectSyncSource::read(
static void writeSourcesToMP4(
Vector<sp<MediaSource> > &sources, bool syncInfoPresent) {
+#if 0
sp<MPEG4Writer> writer =
new MPEG4Writer(gWriteMP4Filename.string());
+#else
+ sp<MPEG2TSWriter> writer =
+ new MPEG2TSWriter(gWriteMP4Filename.string());
+#endif
// at most one minute.
writer->setMaxFileDuration(60000000ll);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1bbf9ea..e93e684 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -67,7 +67,6 @@ import android.location.LocationManager;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
-import android.net.DownloadManager;
import android.net.ThrottleManager;
import android.net.IThrottleManager;
import android.net.Uri;
@@ -103,6 +102,8 @@ import android.view.inputmethod.InputMethodManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
+import com.trustedlogic.trustednfc.android.NfcManager;
+import com.trustedlogic.trustednfc.android.INfcManager;
import com.android.internal.os.IDropBoxManagerService;
@@ -172,6 +173,7 @@ class ContextImpl extends Context {
private static ThrottleManager sThrottleManager;
private static WifiManager sWifiManager;
private static LocationManager sLocationManager;
+ private static NfcManager sNfcManager;
private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
new HashMap<String, SharedPreferencesImpl>();
@@ -970,6 +972,8 @@ class ContextImpl extends Context {
return getClipboardManager();
} else if (WALLPAPER_SERVICE.equals(name)) {
return getWallpaperManager();
+ } else if (NFC_SERVICE.equals(name)) {
+ return getNfcManager();
} else if (DROPBOX_SERVICE.equals(name)) {
return getDropBoxManager();
} else if (DEVICE_POLICY_SERVICE.equals(name)) {
@@ -1205,6 +1209,21 @@ class ContextImpl extends Context {
return mDownloadManager;
}
+ private NfcManager getNfcManager()
+ {
+ synchronized (sSync) {
+ if (sNfcManager == null) {
+ IBinder b = ServiceManager.getService(NFC_SERVICE);
+ if (b == null) {
+ return null;
+ }
+ INfcManager service = INfcManager.Stub.asInterface(b);
+ sNfcManager = new NfcManager(service, mMainThread.getHandler());
+ }
+ }
+ return sNfcManager;
+ }
+
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 1f220d2..c6fef4f 100644
--- a/core/java/android/net/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.net;
+package android.app;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -22,6 +22,8 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.CursorWrapper;
+import android.net.ConnectivityManager;
+import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0100550..693be21 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1207,7 +1207,7 @@ public abstract class Context {
* <dt> {@link #UI_MODE_SERVICE} ("uimode")
* <dd> An {@link android.app.UiModeManager} for controlling UI modes.
* <dt> {@link #DOWNLOAD_SERVICE} ("download")
- * <dd> A {@link android.net.DownloadManager} for requesting HTTP downloads
+ * <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -1256,7 +1256,7 @@ public abstract class Context {
* @see #UI_MODE_SERVICE
* @see android.app.UiModeManager
* @see #DOWNLOAD_SERVICE
- * @see android.net.DownloadManager
+ * @see android.app.DownloadManager
*/
public abstract Object getSystemService(String name);
@@ -1539,7 +1539,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.net.DownloadManager} for requesting HTTP downloads.
+ * {@link android.app.DownloadManager} for requesting HTTP downloads.
*
* @see #getSystemService
*/
@@ -1555,6 +1555,16 @@ public abstract class Context {
public static final String SIP_SERVICE = "sip";
/**
+ * Use with {@link #getSystemService} to retrieve an
+ * {@link com.trustedlogic.trustednfc.android.INfcManager.INfcManager} for
+ * accessing NFC methods.
+ *
+ * @see #getSystemService
+ * @hide
+ */
+ public static final String NFC_SERVICE = "nfc";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/res/ObbInfo.java b/core/java/android/content/res/ObbInfo.java
index 838c5ff..7b962e5 100644
--- a/core/java/android/content/res/ObbInfo.java
+++ b/core/java/android/content/res/ObbInfo.java
@@ -20,9 +20,9 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * Basic information about a Opaque Binary Blob (OBB) that reflects
- * the info from the footer on the OBB file.
- * @hide
+ * Basic information about a Opaque Binary Blob (OBB) that reflects the info
+ * from the footer on the OBB file. This information may be manipulated by a
+ * developer with the <code>obbtool</code> program in the Android SDK.
*/
public class ObbInfo implements Parcelable {
/** Flag noting that this OBB is an overlay patch for a base OBB. */
@@ -43,7 +43,8 @@ public class ObbInfo implements Parcelable {
*/
public int flags;
- public ObbInfo() {
+ // Only allow things in this package to instantiate.
+ /* package */ ObbInfo() {
}
public String toString() {
diff --git a/core/java/android/content/res/ObbScanner.java b/core/java/android/content/res/ObbScanner.java
index eb383c3..572b75e 100644
--- a/core/java/android/content/res/ObbScanner.java
+++ b/core/java/android/content/res/ObbScanner.java
@@ -16,25 +16,43 @@
package android.content.res;
+import java.io.File;
+import java.io.IOException;
+
/**
- * Class to scan Opaque Binary Blob (OBB) files.
- * @hide
+ * Class to scan Opaque Binary Blob (OBB) files. Use this to get information
+ * about an OBB file for use in a program via {@link ObbInfo}.
*/
public class ObbScanner {
// Don't allow others to instantiate this class
private ObbScanner() {}
- public static ObbInfo getObbInfo(String filePath) {
+ /**
+ * Scan a file for OBB information.
+ *
+ * @param filePath path to the OBB file to be scanned.
+ * @return ObbInfo object information corresponding to the file path
+ * @throws IllegalArgumentException if the OBB file couldn't be found
+ * @throws IOException if the OBB file couldn't be read
+ */
+ public static ObbInfo getObbInfo(String filePath) throws IOException {
if (filePath == null) {
- return null;
+ throw new IllegalArgumentException("file path cannot be null");
}
- ObbInfo obbInfo = new ObbInfo();
- if (!getObbInfo_native(filePath, obbInfo)) {
- throw new IllegalArgumentException("Could not read OBB file: " + filePath);
+ final File obbFile = new File(filePath);
+ if (!obbFile.exists()) {
+ throw new IllegalArgumentException("OBB file does not exist: " + filePath);
}
+
+ final String canonicalFilePath = obbFile.getCanonicalPath();
+
+ ObbInfo obbInfo = new ObbInfo();
+ getObbInfo_native(canonicalFilePath, obbInfo);
+
return obbInfo;
}
- private native static boolean getObbInfo_native(String filePath, ObbInfo obbInfo);
+ private native static void getObbInfo_native(String filePath, ObbInfo obbInfo)
+ throws IOException;
}
diff --git a/core/java/android/os/storage/OnObbStateChangeListener.java b/core/java/android/os/storage/OnObbStateChangeListener.java
new file mode 100644
index 0000000..a2d0a56
--- /dev/null
+++ b/core/java/android/os/storage/OnObbStateChangeListener.java
@@ -0,0 +1,31 @@
+/*
+ * 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.os.storage;
+
+/**
+ * Used for receiving notifications from {@link StorageManager}.
+ */
+public abstract class OnObbStateChangeListener {
+ /**
+ * Called when an OBB has changed states.
+ *
+ * @param path path to the OBB file the state change has happened on
+ * @param state the current state of the OBB
+ */
+ public void onObbStateChange(String path, String state) {
+ }
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index df0b69c..14da00a 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -23,13 +23,28 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
/**
- * StorageManager is the interface to the systems storage service.
+ * StorageManager is the interface to the systems storage service. The storage
+ * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
+ * <p>
+ * OBBs contain a filesystem that maybe be encrypted on disk and mounted
+ * on-demand from an application. OBBs are a good way of providing large amounts
+ * of binary assets without packaging them into APKs as they may be multiple
+ * gigabytes in size. However, due to their size, they're most likely stored in
+ * a shared storage pool accessible from all programs. The system does not
+ * guarantee the security of the OBB file itself: if any program modifies the
+ * OBB, there is no guarantee that a read from that OBB will produce the
+ * expected output.
+ * <p>
* Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
- * of {@link android.content.Context#STORAGE_SERVICE}.
+ * {@link android.content.Context#getSystemService(java.lang.String)} with an
+ * argument of {@link android.content.Context#STORAGE_SERVICE}.
*/
public class StorageManager
@@ -75,11 +90,113 @@ public class StorageManager
/**
* Binder listener for OBB action results.
*/
- private final ObbActionBinderListener mObbActionListener = new ObbActionBinderListener();
- private class ObbActionBinderListener extends IObbActionListener.Stub {
+ private final ObbActionListener mObbActionListener = new ObbActionListener();
+
+ private class ObbActionListener extends IObbActionListener.Stub {
+ private List<WeakReference<ObbListenerDelegate>> mListeners = new LinkedList<WeakReference<ObbListenerDelegate>>();
+
@Override
public void onObbResult(String filename, String status) throws RemoteException {
- Log.i(TAG, "filename = " + filename + ", result = " + status);
+ synchronized (mListeners) {
+ final Iterator<WeakReference<ObbListenerDelegate>> iter = mListeners.iterator();
+ while (iter.hasNext()) {
+ final WeakReference<ObbListenerDelegate> ref = iter.next();
+
+ final ObbListenerDelegate delegate = (ref == null) ? null : ref.get();
+ if (delegate == null) {
+ iter.remove();
+ continue;
+ }
+
+ delegate.sendObbStateChanged(filename, status);
+ }
+ }
+ }
+
+ public void addListener(OnObbStateChangeListener listener) {
+ if (listener == null) {
+ return;
+ }
+
+ synchronized (mListeners) {
+ final Iterator<WeakReference<ObbListenerDelegate>> iter = mListeners.iterator();
+ while (iter.hasNext()) {
+ final WeakReference<ObbListenerDelegate> ref = iter.next();
+
+ final ObbListenerDelegate delegate = (ref == null) ? null : ref.get();
+ if (delegate == null) {
+ iter.remove();
+ continue;
+ }
+
+ /*
+ * If we're already in the listeners, we don't need to be in
+ * there again.
+ */
+ if (listener.equals(delegate.getListener())) {
+ return;
+ }
+ }
+
+ final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
+ mListeners.add(new WeakReference<ObbListenerDelegate>(delegate));
+ }
+ }
+ }
+
+ /**
+ * Private class containing sender and receiver code for StorageEvents.
+ */
+ private class ObbListenerDelegate {
+ private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
+ private final Handler mHandler;
+
+ ObbListenerDelegate(OnObbStateChangeListener listener) {
+ mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
+ mHandler = new Handler(mTgtLooper) {
+ @Override
+ public void handleMessage(Message msg) {
+ final OnObbStateChangeListener listener = getListener();
+ if (listener == null) {
+ return;
+ }
+
+ StorageEvent e = (StorageEvent) msg.obj;
+
+ if (msg.what == StorageEvent.EVENT_OBB_STATE_CHANGED) {
+ ObbStateChangedStorageEvent ev = (ObbStateChangedStorageEvent) e;
+ listener.onObbStateChange(ev.path, ev.state);
+ } else {
+ Log.e(TAG, "Unsupported event " + msg.what);
+ }
+ }
+ };
+ }
+
+ OnObbStateChangeListener getListener() {
+ if (mObbEventListenerRef == null) {
+ return null;
+ }
+ return mObbEventListenerRef.get();
+ }
+
+ void sendObbStateChanged(String path, String state) {
+ ObbStateChangedStorageEvent e = new ObbStateChangedStorageEvent(path, state);
+ mHandler.sendMessage(e.getMessage());
+ }
+ }
+
+ /**
+ * Message sent during an OBB status change event.
+ */
+ private class ObbStateChangedStorageEvent extends StorageEvent {
+ public final String path;
+ public final String state;
+
+ public ObbStateChangedStorageEvent(String path, String state) {
+ super(EVENT_OBB_STATE_CHANGED);
+ this.path = path;
+ this.state = state;
}
}
@@ -88,8 +205,9 @@ public class StorageManager
* and the target looper handler.
*/
private class StorageEvent {
- public static final int EVENT_UMS_CONNECTION_CHANGED = 1;
- public static final int EVENT_STORAGE_STATE_CHANGED = 2;
+ static final int EVENT_UMS_CONNECTION_CHANGED = 1;
+ static final int EVENT_STORAGE_STATE_CHANGED = 2;
+ static final int EVENT_OBB_STATE_CHANGED = 3;
private Message mMessage;
@@ -300,19 +418,27 @@ public class StorageManager
* specified, it is supplied to the mounting process to be used in any
* encryption used in the OBB.
* <p>
+ * The OBB will remain mounted for as long as the StorageManager reference
+ * is held by the application. As soon as this reference is lost, the OBBs
+ * in use will be unmounted. The {@link OnObbStateChangeListener} registered with
+ * this call will receive all further OBB-related events until it goes out
+ * of scope. If the caller is not interested in whether the call succeeds,
+ * the <code>listener</code> may be specified as <code>null</code>.
+ * <p>
* <em>Note:</em> you can only mount OBB files for which the OBB tag on the
* file matches a package ID that is owned by the calling program's UID.
- * That is, shared UID applications can obtain access to any other
+ * That is, shared UID applications can attempt to mount any other
* application's OBB that shares its UID.
- * <p>
- * STOPSHIP document more; discuss lack of guarantees of security
*
* @param filename the path to the OBB file
- * @param key decryption key
+ * @param key secret used to encrypt the OBB; may be <code>null</code> if no
+ * encryption was used on the OBB.
* @return whether the mount call was successfully queued or not
+ * @throws IllegalArgumentException when the OBB is already mounted
*/
- public boolean mountObb(String filename, String key) {
+ public boolean mountObb(String filename, String key, OnObbStateChangeListener listener) {
try {
+ mObbActionListener.addListener(listener);
mMountService.mountObb(filename, key, mObbActionListener);
return true;
} catch (RemoteException e) {
@@ -323,15 +449,20 @@ public class StorageManager
}
/**
- * Unmount an Opaque Binary Blob (OBB) file. If the <code>force</code> flag
- * is true, it will kill any application needed to unmount the given OBB.
+ * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
+ * <code>force</code> flag is true, it will kill any application needed to
+ * unmount the given OBB (even the calling application).
+ * <p>
+ * The {@link OnObbStateChangeListener} registered with this call will receive all
+ * further OBB-related events until it goes out of scope. If the caller is
+ * not interested in whether the call succeeded, the listener may be
+ * specified as <code>null</code>.
* <p>
* <em>Note:</em> you can only mount OBB files for which the OBB tag on the
* file matches a package ID that is owned by the calling program's UID.
* That is, shared UID applications can obtain access to any other
* application's OBB that shares its UID.
* <p>
- * STOPSHIP document more; discuss lack of guarantees of security
*
* @param filename path to the OBB file
* @param force whether to kill any programs using this in order to unmount
@@ -339,8 +470,10 @@ public class StorageManager
* @return whether the unmount call was successfully queued or not
* @throws IllegalArgumentException when OBB is not already mounted
*/
- public boolean unmountObb(String filename, boolean force) throws IllegalArgumentException {
+ public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener)
+ throws IllegalArgumentException {
try {
+ mObbActionListener.addListener(listener);
mMountService.unmountObb(filename, force, mObbActionListener);
return true;
} catch (RemoteException e) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1dd2420..90cd840 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1640,6 +1640,86 @@ public final class Settings {
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
/**
+ * Whether nfc is enabled/disabled
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_ON = "nfc_on";
+
+ /**
+ * Whether nfc secure element is enabled/disabled
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_SECURE_ELEMENT_ON = "nfc_secure_element_on";
+
+ /**
+ * Whether nfc secure element is enabled/disabled
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_SECURE_ELEMENT_ID = "nfc_secure_element_id";
+
+ /**
+ * LLCP LTO value
+ * @hide
+ */
+ public static final String NFC_LLCP_LTO = "nfc_llcp_lto";
+
+ /**
+ * LLCP MIU value
+ * @hide
+ */
+ public static final String NFC_LLCP_MIU = "nfc_llcp_miu";
+
+ /**
+ * LLCP WKS value
+ * @hide
+ */
+ public static final String NFC_LLCP_WKS = "nfc_llcp_wks";
+
+ /**
+ * LLCP OPT value
+ * @hide
+ */
+ public static final String NFC_LLCP_OPT = "nfc_llcp_opt";
+
+ /**
+ * NFC Discovery Reader A
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_DISCOVERY_A = "nfc_discovery_a";
+
+ /**
+ * NFC Discovery Reader B
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_DISCOVERY_B = "nfc_discovery_b";
+
+ /**
+ * NFC Discovery Reader Felica
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_DISCOVERY_F = "nfc_discovery_felica";
+
+ /**
+ * NFC Discovery Reader 15693
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_DISCOVERY_15693 = "nfc_discovery_15693";
+
+ /**
+ * NFC Discovery NFCIP
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String NFC_DISCOVERY_NFCIP = "nfc_discovery_nfcip";
+
+ /**
* Show pointer location on screen?
* 0 = no
* 1 = yes
@@ -1804,7 +1884,19 @@ public final class Settings {
SHOW_WEB_SUGGESTIONS,
NOTIFICATION_LIGHT_PULSE,
SIP_CALL_OPTIONS,
- SIP_RECEIVE_CALLS
+ SIP_RECEIVE_CALLS,
+ NFC_ON,
+ NFC_SECURE_ELEMENT_ON,
+ NFC_SECURE_ELEMENT_ID,
+ NFC_LLCP_LTO,
+ NFC_LLCP_MIU,
+ NFC_LLCP_WKS,
+ NFC_LLCP_OPT,
+ NFC_DISCOVERY_A,
+ NFC_DISCOVERY_B,
+ NFC_DISCOVERY_F,
+ NFC_DISCOVERY_15693,
+ NFC_DISCOVERY_NFCIP,
};
// Settings moved to Settings.Secure
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7098bf3..24b1158 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -5016,7 +5016,7 @@ public class WebView extends AbsoluteLayout
@Override
public boolean onTouchEvent(MotionEvent ev) {
- if (mNativeClass == 0 || !isClickable() || !isLongClickable()) {
+ if (mNativeClass == 0 || (!isClickable() && !isLongClickable())) {
return false;
}
diff --git a/core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl b/core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl
new file mode 100644
index 0000000..35746ad
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+import com.trustedlogic.trustednfc.android.LlcpPacket;
+
+/**
+ * TODO
+ *
+ * {@hide}
+ */
+interface ILlcpConnectionlessSocket
+{
+
+ void close(int nativeHandle);
+ int getSap(int nativeHandle);
+ LlcpPacket receiveFrom(int nativeHandle);
+ int sendTo(int nativeHandle, in LlcpPacket packet);
+
+} \ No newline at end of file
diff --git a/core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl b/core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl
new file mode 100644
index 0000000..5eb1f3c
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+/**
+ * TODO
+ *
+ * {@hide}
+ */
+interface ILlcpServiceSocket
+{
+
+ int accept(int nativeHandle);
+ void close(int nativeHandle);
+ int getAcceptTimeout(int nativeHandle);
+ void setAcceptTimeout(int nativeHandle, int timeout);
+
+} \ No newline at end of file
diff --git a/core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl b/core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl
new file mode 100644
index 0000000..e9169d8
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+/**
+ * TODO
+ *
+ * {@hide}
+ */
+interface ILlcpSocket
+{
+
+ int close(int nativeHandle);
+ int connect(int nativeHandle, int sap);
+ int connectByName(int nativeHandle, String sn);
+ int getConnectTimeout(int nativeHandle);
+ int getLocalSap(int nativeHandle);
+ int getLocalSocketMiu(int nativeHandle);
+ int getLocalSocketRw(int nativeHandle);
+ int getRemoteSocketMiu(int nativeHandle);
+ int getRemoteSocketRw(int nativeHandle);
+ int receive(int nativeHandle, out byte[] receiveBuffer);
+ int send(int nativeHandle, in byte[] data);
+ void setConnectTimeout(int nativeHandle, int timeout);
+
+}
+
diff --git a/core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl b/core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl
new file mode 100644
index 0000000..1f8d1a4
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+import com.trustedlogic.trustednfc.android.NdefMessage;
+
+/**
+ * TODO
+ *
+ * {@hide}
+ */
+interface INdefTag
+{
+
+ NdefMessage read(int nativeHandle);
+ boolean write(int nativeHandle, in NdefMessage msg);
+
+} \ No newline at end of file
diff --git a/core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl b/core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl
new file mode 100644
index 0000000..ce36ab2
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+import com.trustedlogic.trustednfc.android.ILlcpSocket;
+import com.trustedlogic.trustednfc.android.ILlcpServiceSocket;
+import com.trustedlogic.trustednfc.android.ILlcpConnectionlessSocket;
+import com.trustedlogic.trustednfc.android.INfcTag;
+import com.trustedlogic.trustednfc.android.IP2pTarget;
+import com.trustedlogic.trustednfc.android.IP2pInitiator;
+
+
+/**
+ * Interface that allows controlling NFC activity.
+ *
+ * {@hide}
+ */
+interface INfcManager
+{
+
+ ILlcpSocket getLlcpInterface();
+ ILlcpConnectionlessSocket getLlcpConnectionlessInterface();
+ ILlcpServiceSocket getLlcpServiceInterface();
+ INfcTag getNfcTagInterface();
+ IP2pTarget getP2pTargetInterface();
+ IP2pInitiator getP2pInitiatorInterface();
+
+ void cancel();
+ int createLlcpConnectionlessSocket(int sap);
+ int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength);
+ int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength);
+ int deselectSecureElement();
+ boolean disable();
+ boolean enable();
+ int getOpenTimeout();
+ String getProperties(String param);
+ int[] getSecureElementList();
+ int getSelectedSecureElement();
+ boolean isEnabled();
+ int openP2pConnection();
+ int openTagConnection();
+ int selectSecureElement(int seId);
+ void setOpenTimeout(int timeout);
+ int setProperties(String param, String value);
+
+}
+
diff --git a/core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl b/core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl
new file mode 100644
index 0000000..79543c4
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+import com.trustedlogic.trustednfc.android.NdefMessage;
+
+/**
+ * TODO
+ *
+ * {@hide}
+ */
+interface INfcTag
+{
+
+ int close(int nativeHandle);
+ int connect(int nativeHandle);
+ String getType(int nativeHandle);
+ byte[] getUid(int nativeHandle);
+ boolean isNdef(int nativeHandle);
+ byte[] transceive(int nativeHandle, in byte[] data);
+
+ NdefMessage read(int nativeHandle);
+ boolean write(int nativeHandle, in NdefMessage msg);
+} \ No newline at end of file
diff --git a/core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl b/core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl
new file mode 100644
index 0000000..96819ae
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+/**
+ * TODO
+ *
+ * {@hide}
+ */
+interface IP2pInitiator
+{
+
+ byte[] getGeneralBytes(int nativeHandle);
+ int getMode(int nativeHandle);
+ byte[] receive(int nativeHandle);
+ boolean send(int nativeHandle, in byte[] data);
+
+} \ No newline at end of file
diff --git a/core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl b/core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl
new file mode 100644
index 0000000..8dcdf18
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+/**
+ * TODO
+ *
+ * {@hide}
+ */
+interface IP2pTarget
+{
+
+ byte[] getGeneralBytes(int nativeHandle);
+ int getMode(int nativeHandle);
+ int connect(int nativeHandle);
+ boolean disconnect(int nativeHandle);
+ byte[] transceive(int nativeHandle, in byte[] data);
+
+} \ No newline at end of file
diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpConnectionlessSocket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpConnectionlessSocket.java
new file mode 100644
index 0000000..0270626
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/LlcpConnectionlessSocket.java
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : LlcpConnectionLessSocket.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used
+ * in a connectionless communication
+ *
+ * @since AA02.01
+ * @hide
+ */
+public class LlcpConnectionlessSocket {
+
+
+ private static final String TAG = "LlcpConnectionlessSocket";
+
+ /**
+ * The handle returned by the NFC service and used to identify the LLCP connectionless socket in
+ * every call of this class.
+ *
+ * @hide
+ */
+ protected int mHandle;
+
+
+ /**
+ * The entry point for LLCP Connectionless socket operations.
+ *
+ * @hide
+ */
+ protected ILlcpConnectionlessSocket mService;
+
+
+ /**
+ * Internal constructor for the LlcpConnectionlessSocket class.
+ *
+ * @param service The entry point to the Nfc Service for LLCP Connectionless socket class.
+ * @param handle The handle returned by the NFC service and used to identify
+ * the socket in subsequent calls.
+ * @hide
+ */
+ LlcpConnectionlessSocket(ILlcpConnectionlessSocket service, int handle) {
+ this.mService = service;
+ this.mHandle = handle;
+ }
+
+ /**
+ * Send data to a specific LLCP Connectionless client
+ *
+ * @param packet Service Access Point number related to a LLCP
+ * Connectionless client and a data buffer to send
+ * @throws IOException if the LLCP link has been lost or deactivated.
+ * @since AA02.01
+ */
+ public void sendTo(LlcpPacket packet) throws IOException {
+ try {
+ int result = mService.sendTo(mHandle, packet);
+ // Handle potential errors
+ if (ErrorCodes.isError(result)) {
+ throw new IOException();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in sendTo(): ", e);
+ }
+ }
+
+ /**
+ * Receive data from a LLCP Connectionless client
+ *
+ * @return data data received from a specific LLCP Connectionless client
+ * @throws IOException if the LLCP link has been lost or deactivated.
+ * @see LlcpPacket
+ * @since AA02.01
+ */
+ public LlcpPacket receiveFrom() throws IOException {
+ try {
+ LlcpPacket packet = mService.receiveFrom(mHandle);
+ if (packet != null) {
+ return packet;
+ }else{
+ // Handle potential errors
+ throw new IOException();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in receiveFrom(): ", e);
+ }
+ return null;
+ }
+
+ /**
+ * Close the created Connectionless socket.
+ *
+ * @since AA02.01
+ */
+ public void close() {
+ try {
+ mService.close(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in close(): ", e);
+ }
+ }
+
+ /**
+ * Returns the local Service Access Point number of the socket
+ *
+ * @return sap
+ * @since AA02.01
+ */
+ public int getSap() {
+ int sap = 0;
+
+ try {
+ sap = mService.getSap(mHandle);
+
+ } catch (RemoteException e) {
+
+ e.printStackTrace();
+ }
+ return sap;
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpException.java b/core/java/com/trustedlogic/trustednfc/android/LlcpException.java
new file mode 100644
index 0000000..1e2e2da
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/LlcpException.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : LLCPException.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ * Created : 24-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+/**
+ * Generic exception thrown in case something unexpected happened during a
+ * LLCP communication.
+ *
+ * @since AA02.01
+ * @hide
+ */
+public class LlcpException extends Exception {
+ /**
+ * Constructs a new LlcpException with the current stack trace and the
+ * specified detail message.
+ *
+ * @param s the detail message for this exception.
+ */
+ public LlcpException(String s) {
+ super(s);
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.aidl b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.aidl
new file mode 100644
index 0000000..297a1fe
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+parcelable LlcpPacket;
diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.java
new file mode 100644
index 0000000..af79023
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : LLCPPacket.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ * Created : 25-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a LLCP packet received in a LLCP Connectionless communication;
+ *
+ * @since AA02.01
+ * @hide
+ */
+public class LlcpPacket implements Parcelable {
+
+ private int mRemoteSap;
+
+ private byte[] mDataBuffer;
+
+ /**
+ * Creator class, needed when implementing from Parcelable
+ * {@hide}
+ */
+ public static final Parcelable.Creator<LlcpPacket> CREATOR = new Parcelable.Creator<LlcpPacket>() {
+ public LlcpPacket createFromParcel(Parcel in) {
+ // Remote SAP
+ short sap = (short)in.readInt();
+
+ // Data Buffer
+ int dataLength = in.readInt();
+ byte[] data = new byte[dataLength];
+ in.readByteArray(data);
+
+ return new LlcpPacket(sap, data);
+ }
+
+ public LlcpPacket[] newArray(int size) {
+ return new LlcpPacket[size];
+ }
+ };
+
+
+ /**
+ * Creates a LlcpPacket to be sent to a remote Service Access Point number
+ * (SAP)
+ *
+ * @param sap Remote Service Access Point number
+ * @param data Data buffer
+ * @since AA02.01
+ */
+ public LlcpPacket(int sap, byte[] data) {
+ mRemoteSap = sap;
+ mDataBuffer = data;
+ }
+
+ /**
+ * @hide
+ */
+ public LlcpPacket() {
+ }
+
+ /**
+ * Returns the remote Service Access Point number
+ *
+ * @return remoteSap
+ * @since AA02.01
+ */
+ public int getRemoteSap() {
+ return mRemoteSap;
+ }
+
+ /**
+ * Returns the data buffer
+ *
+ * @return data
+ * @since AA02.01
+ */
+ public byte[] getDataBuffer() {
+ return mDataBuffer;
+ }
+
+ /**
+ * (Parcelable) Describe the parcel
+ * {@hide}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * (Parcelable) Convert current object to a Parcel
+ * {@hide}
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRemoteSap);
+ dest.writeInt(mDataBuffer.length);
+ dest.writeByteArray(mDataBuffer);
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpServiceSocket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpServiceSocket.java
new file mode 100644
index 0000000..a152ecb1
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/LlcpServiceSocket.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : LLCPServerSocket.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * LlcpServiceSocket represents a LLCP Service to be used in a
+ * Connection-oriented communication
+ *
+ * @since AA02.01
+ * @hide
+ */
+public class LlcpServiceSocket {
+
+ private static final String TAG = "LlcpServiceSocket";
+
+ /**
+ * The handle returned by the NFC service and used to identify the LLCP
+ * Service socket in every call of this class.
+ *
+ * @hide
+ */
+ protected int mHandle;
+
+ /**
+ * The entry point for LLCP Service socket operations.
+ *
+ * @hide
+ */
+ protected ILlcpServiceSocket mService;
+
+ private ILlcpSocket mLlcpSocketService;
+
+ static LlcpException convertErrorToLlcpException(int errorCode) {
+ return convertErrorToLlcpException(errorCode, null);
+ }
+
+ static LlcpException convertErrorToLlcpException(int errorCode,
+ String message) {
+ if (message == null) {
+ message = "";
+ } else {
+ message = " (" + message + ")";
+ }
+
+ switch (errorCode) {
+ case ErrorCodes.ERROR_SOCKET_CREATION:
+ return new LlcpException(
+ "Error during the creation of an Llcp socket" + message);
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ return new LlcpException("Not enough ressources are available"
+ + message);
+ default:
+ return new LlcpException("Unkown error code " + errorCode + message);
+ }
+ }
+
+ /**
+ * Internal constructor for the LlcpServiceSocket class.
+ *
+ * @param service
+ * The entry point to the Nfc Service for LlcpServiceSocket
+ * class.
+ * @param handle
+ * The handle returned by the NFC service and used to identify
+ * the socket in subsequent calls.
+ * @hide
+ */
+ LlcpServiceSocket(ILlcpServiceSocket service, ILlcpSocket socketService, int handle) {
+ this.mService = service;
+ this.mHandle = handle;
+ this.mLlcpSocketService = socketService;
+ }
+
+ /**
+ * Wait for incomming connection request from a LLCP client and accept this
+ * request
+ *
+ * @return socket object to be used to communicate with a LLCP client
+ *
+ * @throws IOException
+ * if the llcp link is lost or deactivated
+ * @throws LlcpException
+ * if not enough ressources are available
+ *
+ * @see LlcpSocket
+ * @since AA02.01
+ */
+ public LlcpSocket accept() throws IOException, LlcpException {
+
+ try {
+ int handle = mService.accept(mHandle);
+ // Handle potential errors
+ if (ErrorCodes.isError(handle)) {
+ if (handle == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToLlcpException(handle);
+ }
+ }
+
+ // Build the public LlcpSocket object
+ return new LlcpSocket(mLlcpSocketService, handle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in accept(): ", e);
+ return null;
+ }
+
+ }
+
+ /**
+ * Set the timeout for the accept request
+ *
+ * @param timeout
+ * value of the timeout for the accept request
+ * @since AA02.01
+ */
+ public void setAcceptTimeout(int timeout) {
+ try {
+ mService.setAcceptTimeout(mHandle, timeout);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in setAcceptTimeout(): ", e);
+ }
+ }
+
+ /**
+ * Get the timeout value of the accept request
+ *
+ * @return mTimeout
+ * @since AA02.01
+ */
+ public int getAcceptTimeout() {
+ try {
+ return mService.getAcceptTimeout(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getAcceptTimeout(): ", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Close the created Llcp Service socket
+ *
+ * @since AA02.01
+ */
+ public void close() {
+ try {
+ mService.close(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in close(): ", e);
+ }
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpSocket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpSocket.java
new file mode 100644
index 0000000..e47160c
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/LlcpSocket.java
@@ -0,0 +1,344 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : LlcpClientSocket.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a
+ * connection-oriented communication
+ *
+ * @since AA02.01
+ * @hide
+ */
+public class LlcpSocket {
+
+ private static final String TAG = "LlcpSocket";
+
+ /**
+ * The handle returned by the NFC service and used to identify the LLCP
+ * socket in every call of this class.
+ *
+ * @hide
+ */
+ protected int mHandle;
+
+ /**
+ * The entry point for LLCP socket operations.
+ *
+ * @hide
+ */
+ protected ILlcpSocket mService;
+
+ static LlcpException convertErrorToLlcpException(int errorCode) {
+ return convertErrorToLlcpException(errorCode, null);
+ }
+
+ static LlcpException convertErrorToLlcpException(int errorCode,
+ String message) {
+ if (message == null) {
+ message = "";
+ } else {
+ message = " (" + message + ")";
+ }
+
+ switch (errorCode) {
+ case ErrorCodes.ERROR_SOCKET_CREATION:
+ return new LlcpException(
+ "Error during the creation of an Llcp socket" + message);
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ return new LlcpException("Not enough ressources are available"
+ + message);
+ case ErrorCodes.ERROR_SOCKET_NOT_CONNECTED:
+ return new LlcpException("Socket not connected to an Llcp Service"
+ + message);
+ default:
+ return new LlcpException("Unkown error code " + errorCode + message);
+ }
+ }
+
+ /**
+ * Internal constructor for the LlcpSocket class.
+ *
+ * @param service
+ * The entry point to the Nfc Service for LlcpServiceSocket
+ * class.
+ * @param handle
+ * The handle returned by the NFC service and used to identify
+ * the socket in subsequent calls.
+ * @hide
+ */
+ LlcpSocket(ILlcpSocket service, int handle) {
+ this.mService = service;
+ this.mHandle = handle;
+ }
+
+ /**
+ * Connect request to a specific LLCP Service by its SAP.
+ *
+ * @param sap
+ * Service Access Point number of the LLCP Service
+ * @throws IOException
+ * if the LLCP has been lost or deactivated.
+ * @throws LlcpException
+ * if the connection request is rejected by the remote LLCP
+ * Service
+ * @since AA02.01
+ */
+ public void connect(int sap) throws IOException, LlcpException {
+ try {
+ int result = mService.connect(mHandle, sap);
+ // Handle potential errors
+ if (ErrorCodes.isError(result)) {
+ if (result == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToLlcpException(result);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in accept(): ", e);
+ }
+ }
+
+ /**
+ * Connect request to a specific LLCP Service by its Service Name.
+ *
+ * @param sn
+ * Service Name of the LLCP Service
+ * @throws IOException
+ * if the LLCP has been lost or deactivated.
+ * @throws LlcpException
+ * if the connection request is rejected by the remote LLCP
+ * Service
+ * @since AA02.01
+ */
+ public void connect(String sn) throws IOException, LlcpException {
+ try {
+ int result = mService.connectByName(mHandle, sn);
+ // Handle potential errors
+ if (ErrorCodes.isError(result)) {
+ if (result == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToLlcpException(result);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in accept(): ", e);
+ }
+ }
+
+ /**
+ * Set the timeout for the connect request
+ *
+ * @param timeout
+ * timeout value for the connect request
+ * @since AA02.01
+ */
+ public void setConnectTimeout(int timeout) {
+ try {
+ mService.setConnectTimeout(mHandle, timeout);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in setConnectTimeout(): ", e);
+ }
+ }
+
+ /**
+ * Get the timeout value of the connect request
+ *
+ * @return mTimeout
+ * @since AA02.01
+ */
+ public int getConnectTimeout() {
+ try {
+ return mService.getConnectTimeout(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getConnectTimeout(): ", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Disconnect request to the connected LLCP socket and close the created
+ * socket.
+ *
+ * @throws IOException
+ * if the LLCP has been lost or deactivated.
+ * @since AA02.01
+ */
+ public void close() throws IOException {
+ try {
+ int result = mService.close(mHandle);
+ // Handle potential errors
+ if (ErrorCodes.isError(result)) {
+ throw new IOException();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in close(): ", e);
+ }
+ }
+
+ /**
+ * Send data to the connected LLCP Socket.
+ *
+ * @throws IOException
+ * if the LLCP has been lost or deactivated.
+ * @since AA02.01
+ */
+ public void send(byte[] data) throws IOException {
+ try {
+ int result = mService.send(mHandle, data);
+ // Handle potential errors
+ if (ErrorCodes.isError(result)) {
+ throw new IOException();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in send(): ", e);
+ }
+ }
+
+ /**
+ * Receive data from the connected LLCP socket
+ *
+ * @param receiveBuffer
+ * a buffer for the received data
+ * @return length length of the data received
+ * @throws IOException
+ * if the LLCP has been lost or deactivated.
+ * @since AA02.01
+ */
+ public int receive(byte[] receiveBuffer) throws IOException {
+ int receivedLength = 0;
+ try {
+ receivedLength = mService.receive(mHandle, receiveBuffer);
+ if(receivedLength == 0){
+ throw new IOException();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in send(): ", e);
+ }
+
+ return receivedLength;
+ }
+
+ /**
+ * Returns the local Service Access Point number of the socket
+ *
+ * @return localSap
+ * @since AA02.01
+ */
+ public int getLocalSap() {
+ try {
+ return mService.getLocalSap(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getLocalSap(): ", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the local Maximum Information Unit(MIU) of the socket
+ *
+ * @return miu
+ * @since AA02.01
+ */
+ public int getLocalSocketMiu() {
+ try {
+ return mService.getLocalSocketMiu(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getLocalSocketMiu(): ", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the local Receive Window(RW) of the socket
+ *
+ * @return rw
+ * @since AA02.01
+ */
+ public int getLocalSocketRw() {
+ try {
+ return mService.getLocalSocketRw(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getLocalSocketRw(): ", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the remote Maximum Information Unit(MIU) of the socket.
+ * <p>
+ * This method must be called when the socket is in CONNECTED_STATE
+ *
+ * @return remoteMiu
+ * @throws LlcpException
+ * if the LlcpClientSocket is not in a CONNECTED_STATE
+ * @since AA02.01
+ */
+ public int getRemoteSocketMiu() throws LlcpException {
+ try {
+ int result = mService.getRemoteSocketMiu(mHandle);
+ if(result != ErrorCodes.ERROR_SOCKET_NOT_CONNECTED){
+ return result;
+ }else{
+ throw convertErrorToLlcpException(result);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getRemoteSocketMiu(): ", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the remote Receive Window(RW) of the connected remote socket.
+ * <p>
+ * This method must be called when the socket is in CONNECTED_STATE
+ *
+ * @return rw
+ * @throws LlcpException
+ * if the LlcpClientSocket is not in a CONNECTED_STATE
+ * @since AA02.01
+ */
+ public int getRemoteSocketRw() throws LlcpException {
+ try {
+ int result = mService.getRemoteSocketRw(mHandle);
+ if( result != ErrorCodes.ERROR_SOCKET_NOT_CONNECTED){
+ return result;
+ }else{
+ throw convertErrorToLlcpException(result);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getRemoteSocketRw(): ", e);
+ return 0;
+ }
+ }
+
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefMessage.aidl b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.aidl
new file mode 100644
index 0000000..e60f4e8
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+parcelable NdefMessage;
diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefMessage.java b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.java
new file mode 100644
index 0000000..f03b604
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.java
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NDEFMessage.java
+ * Original-Author : Trusted Logic S.A. (Jeremie Corbier)
+ * Created : 05-10-2009
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents an NDEF message as specified by the <a
+ * href="http://www.nfc-forum.org/">NFC Forum</a>.
+ *
+ * @see NdefRecord
+ *
+ * @since AA01.04
+ * @hide
+ */
+public class NdefMessage implements Parcelable {
+ /* Flag values */
+ private static final int FLAG_MB = 0x80;
+ private static final int FLAG_ME = 0x40;
+ private static final int FLAG_CF = 0x20;
+ private static final int FLAG_SR = 0x10;
+ private static final int FLAG_IL = 0x08;
+
+ /**
+ * Array of {@link NdefRecord} composing this message.
+ */
+ private NdefRecord[] mRecords;
+
+ /**
+ * Builds an NDEF message.
+ *
+ * @param data raw NDEF message data
+ *
+ * @throws NFCException
+ */
+ public NdefMessage(byte[] data) throws NfcException {
+ if (parseNdefMessage(data) == -1)
+ throw new NfcException("Error while parsing NDEF message");
+ }
+
+ /**
+ * Builds an NDEF message.
+ *
+ * @param records
+ * an array of already created NDEF records
+ */
+ public NdefMessage(NdefRecord[] records) {
+ mRecords = new NdefRecord[records.length];
+
+ System.arraycopy(records, 0, mRecords, 0, records.length);
+ }
+
+ /**
+ * Returns the NDEF message as a byte array.
+ *
+ * @return the message as a byte array
+ */
+ public byte[] toByteArray() {
+ if ((mRecords == null) || (mRecords.length == 0))
+ return null;
+
+ byte[] msg = {};
+
+ for (int i = 0; i < mRecords.length; i++) {
+ byte[] record = mRecords[i].toByteArray();
+ byte[] tmp = new byte[msg.length + record.length];
+
+ /* Make sure the Message Begin flag is set only for the first record */
+ if (i == 0)
+ record[0] |= FLAG_MB;
+ else
+ record[0] &= ~FLAG_MB;
+
+ /* Make sure the Message End flag is set only for the last record */
+ if (i == (mRecords.length - 1))
+ record[0] |= FLAG_ME;
+ else
+ record[0] &= ~FLAG_ME;
+
+ System.arraycopy(msg, 0, tmp, 0, msg.length);
+ System.arraycopy(record, 0, tmp, msg.length, record.length);
+
+ msg = tmp;
+ }
+
+ return msg;
+ }
+
+ /**
+ * Returns an array of {@link NdefRecord} composing this message.
+ *
+ * @return mRecords
+ *
+ * @since AA02.01
+ */
+ public NdefRecord[] getRecords(){
+ return mRecords;
+ }
+
+ private native int parseNdefMessage(byte[] data);
+
+ /**
+ * (Parcelable) Describe the parcel
+ * {@hide}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * (Parcelable) Convert current object to a Parcel
+ * {@hide}
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRecords.length);
+ dest.writeTypedArray(mRecords, 0);
+ }
+
+ /**
+ * Creator class, needed when implementing from Parcelable
+ * {@hide}
+ */
+ public static final Parcelable.Creator<NdefMessage> CREATOR = new Parcelable.Creator<NdefMessage>() {
+ public NdefMessage createFromParcel(Parcel in) {
+ int recordsLength = in.readInt();
+ NdefRecord[] records = new NdefRecord[recordsLength];
+ in.readTypedArray(records, NdefRecord.CREATOR);
+ return new NdefMessage(records);
+ }
+
+ public NdefMessage[] newArray(int size) {
+ return new NdefMessage[size];
+ }
+ };
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefRecord.aidl b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.aidl
new file mode 100644
index 0000000..9d95174
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android;
+
+parcelable NdefRecord;
diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefRecord.java b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.java
new file mode 100644
index 0000000..a0257fe
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.java
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NdefRecord.java
+ * Original-Author : Trusted Logic S.A. (Jeremie Corbier)
+ * Created : 05-10-2009
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import android.location.Location;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An NDEF record as specified by the <a href="http://www.nfc-forum.org/">NFC
+ * Forum</a>.
+ *
+ * @see NdefMessage
+ *
+ * @since AA01.04
+ * @hide
+ */
+public class NdefRecord implements Parcelable {
+
+ /**
+ * Type Name Format - Empty record
+ */
+ public static final short TNF_EMPTY = 0x0;
+
+ /**
+ * Type Name Format - NFC Forum-defined type
+ */
+ public static final short TNF_WELL_KNOWN_TYPE = 0x1;
+
+ /**
+ * Type Name Format - RFC2045 MIME type
+ */
+ public static final short TNF_MIME_MEDIA_TYPE = 0x2;
+
+ /**
+ * Type Name Format - Absolute URI
+ */
+ public static final short TNF_ABSOLUTE_URI = 0x3;
+
+ /**
+ * Type Name Format - User-defined type
+ */
+ public static final short TNF_EXTERNAL_TYPE = 0x4;
+
+ /**
+ * Type Name Format - Unknown type
+ */
+ public static final short TNF_UNKNOWN = 0x5;
+
+ /**
+ * Type Name Format - Unchanged. This TNF is used for chunked records, so
+ * that middle records inherits from the first record's type.
+ */
+ public static final short TNF_UNCHANGED = 0x6;
+
+ /**
+ * NFC Forum-defined Type - Smart Poster
+ */
+ public static final byte[] TYPE_SMART_POSTER = { 0x53, 0x70 };
+
+ /**
+ * NFC Forum-defined Type - Text
+ */
+ public static final byte[] TYPE_TEXT = { 0x54 };
+
+ /**
+ * NFC Forum-defined Type - URI
+ */
+ public static final byte[] TYPE_URI = { 0x55 };
+
+ /**
+ * NFC Forum-defined Global Type - Connection Handover Request
+ */
+ public static final byte[] TYPE_HANDOVER_REQUEST = { 0x48, 0x72 };
+
+ /**
+ * NFC Forum-defined Global Type - Connection Handover Select
+ */
+ public static final byte[] TYPE_HANDOVER_SELECT = { 0x48, 0x73 };
+
+ /**
+ * NFC Forum-defined Global Type - Connection Handover Carrier
+ */
+ public static final byte[] TYPE_HANDOVER_CARRIER = { 0x48, 0x63 };
+
+ /**
+ * NFC Forum-defined Local Type - Alternative Carrier
+ */
+ public static final byte[] TYPE_ALTERNATIVE_CARRIER = { 0x61, 0x63 };
+
+ /* Flag values */
+ private static final int FLAG_MB = 0x80;
+ private static final int FLAG_ME = 0x40;
+ private static final int FLAG_CF = 0x20;
+ private static final int FLAG_SR = 0x10;
+ private static final int FLAG_IL = 0x08;
+
+ /**
+ * Record Flags
+ */
+ private short mFlags = 0;
+
+ /**
+ * Record Type Name Format
+ */
+ private short mTnf = 0;
+
+ /**
+ * Record Type
+ */
+ private byte[] mType = null;
+
+ /**
+ * Record Identifier
+ */
+ private byte[] mId = null;
+
+ /**
+ * Record Payload
+ */
+ private byte[] mPayload = null;
+
+ /**
+ * Creates an NdefRecord given its Type Name Format, its type, its id and
+ * its.
+ *
+ * @param tnf
+ * Type Name Format
+ * @param type
+ * record type
+ * @param id
+ * record id (optional, can be null)
+ * @param data
+ * record payload
+ */
+ public NdefRecord(short tnf, byte[] type, byte[] id, byte[] data) {
+
+ /* generate flag */
+ mFlags = FLAG_MB | FLAG_ME;
+
+ /* Determine if it is a short record */
+ if(data.length < 0xFF)
+ {
+ mFlags |= FLAG_SR;
+ }
+
+ /* Determine if an id is present */
+ if(id.length != 0)
+ {
+ mFlags |= FLAG_IL;
+ }
+
+ mTnf = tnf;
+ mType = (byte[]) type.clone();
+ mId = (byte[]) id.clone();
+ mPayload = (byte[]) data.clone();
+ }
+
+ /**
+ * Appends data to the record's payload.
+ *
+ * @param data
+ * Data to be added to the record.
+ */
+ public void appendPayload(byte[] data) {
+ byte[] newPayload = new byte[mPayload.length + data.length];
+
+ System.arraycopy(mPayload, 0, newPayload, 0, mPayload.length);
+ System.arraycopy(data, 0, newPayload, mPayload.length, data.length);
+
+ mPayload = newPayload;
+ }
+
+ /**
+ * Returns record as a byte array.
+ *
+ * @return record as a byte array.
+ */
+ public byte[] toByteArray() {
+ return generate(mFlags, mTnf, mType, mId, mPayload);
+ }
+
+ private native byte[] generate(short flags, short tnf, byte[] type,
+ byte[] id, byte[] data);
+
+ /**
+ * (Parcelable) Describe the parcel
+ * {@hide}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * (Parcelable) Convert current object to a Parcel
+ * {@hide}
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTnf);
+ dest.writeInt(mType.length);
+ dest.writeByteArray(mType);
+ dest.writeInt(mId.length);
+ dest.writeByteArray(mId);
+ dest.writeInt(mPayload.length);
+ dest.writeByteArray(mPayload);
+ }
+
+ /**
+ * Creator class, needed when implementing from Parcelable
+ * {@hide}
+ */
+ public static final Parcelable.Creator<NdefRecord> CREATOR = new Parcelable.Creator<NdefRecord>() {
+ public NdefRecord createFromParcel(Parcel in) {
+ // TNF
+ short tnf = (short)in.readInt();
+ // Type
+ int typeLength = in.readInt();
+ byte[] type = new byte[typeLength];
+ in.readByteArray(type);
+ // ID
+ int idLength = in.readInt();
+ byte[] id = new byte[idLength];
+ in.readByteArray(id);
+ // Payload
+ int payloadLength = in.readInt();
+ byte[] payload = new byte[payloadLength];
+ in.readByteArray(payload);
+
+ return new NdefRecord(tnf, type, id, payload);
+ }
+
+ public NdefRecord[] newArray(int size) {
+ return new NdefRecord[size];
+ }
+ };
+
+ /**
+ * Returns record TNF
+ *
+ * @return mTnf
+ */
+ public int getTnf(){
+ return mTnf;
+ }
+
+ /**
+ * Returns record TYPE
+ *
+ * @return mType
+ */
+ public byte[] getType(){
+ return mType;
+ }
+
+ /**
+ * Returns record ID
+ *
+ * @return mId
+ */
+ public byte[] getId(){
+ return mId;
+ }
+
+ /**
+ * Returns record Payload
+ *
+ * @return mPayload
+ */
+ public byte[] getPayload(){
+ return mPayload;
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefTag.java b/core/java/com/trustedlogic/trustednfc/android/NdefTag.java
new file mode 100644
index 0000000..1d99241
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NdefTag.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NDEFTag.java
+ * Original-Author : Trusted Logic S.A. (Jeremie Corbier)
+ * Created : 04-12-2009
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * NdefTag represents tags complying with the NFC Forum's NFC Data Exchange
+ * Format.
+ *
+ * @since AA01.04
+ * @hide
+ */
+public class NdefTag extends NfcTag {
+
+ private static final String TAG = "NdefTag";
+
+
+ public NdefTag(NfcTag tag){
+ super(tag.mService,tag.mHandle);
+ this.isConnected = tag.isConnected;
+ this.isClosed = tag.isClosed;
+ tag.isClosed = false;
+ }
+
+ /**
+ * Internal constructor for the NfcNdefTag class.
+ *
+ * @param service The entry point to the Nfc Service for NfcNdefTag class.
+ * @param handle The handle returned by the NFC service and used to identify
+ * the tag in subsequent calls.
+ * @hide
+ */
+ NdefTag(INfcTag service, int handle) {
+ super(service, handle);
+ }
+
+ /**
+ * Read NDEF data from an NDEF tag.
+ *
+ * @return the NDEF message read from the tag.
+ * @throws NfcException if the tag is not NDEF-formatted.
+ * @throws IOException if the target has been lost or the connection has
+ * been closed.
+ * @see NdefMessage
+ */
+ public NdefMessage read() throws NfcException, IOException {
+ // Check state
+ checkState();
+
+ //Check if the tag is Ndef compliant
+ if(isNdef != true){
+ isNdef = isNdef();
+ if(isNdef != true) {
+ throw new NfcException("Tag is not NDEF compliant");
+ }
+ }
+
+ // Perform transceive
+ try {
+ NdefMessage msg = mService.read(mHandle);
+ if (msg == null) {
+ throw new IOException("NDEF read failed");
+ }
+ return msg;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in read(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Write NDEF data to an NDEF-compliant tag.
+ *
+ * @param msg NDEF message to be written to the tag.
+ * @throws NfcException if the tag is not NDEF formatted.
+ * @throws IOException if the target has been lost or the connection has
+ * been closed.
+ * @see NdefMessage
+ */
+ public void write(NdefMessage msg) throws NfcException, IOException {
+ // Check state
+ checkState();
+
+ //Check if the tag is Ndef compliant
+ if(isNdef != true){
+ isNdef = isNdef();
+ if(isNdef != true) {
+ throw new NfcException("Tag is not NDEF compliant");
+ }
+ }
+
+ // Perform transceive
+ try {
+ boolean isSuccess = mService.write(mHandle, msg);
+ if (!isSuccess) {
+ throw new IOException("NDEF write failed");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in write(): ", e);
+ }
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/NfcException.java b/core/java/com/trustedlogic/trustednfc/android/NfcException.java
new file mode 100644
index 0000000..2497c15
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NfcException.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NFCException.java
+ * Original-Author : Trusted Logic S.A. (Jeremie Corbier)
+ * Created : 26-08-2009
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+/**
+ * Generic exception thrown in case something unexpected happened during the
+ * NFCManager operations.
+ *
+ * @since AA01.04
+ * @hide
+ */
+public class NfcException extends Exception {
+ /**
+ * Constructs a new NfcException with the current stack trace and the
+ * specified detail message.
+ *
+ * @param s the detail message for this exception.
+ */
+ public NfcException(String s) {
+ super(s);
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/NfcManager.java b/core/java/com/trustedlogic/trustednfc/android/NfcManager.java
new file mode 100644
index 0000000..98ab5bf
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NfcManager.java
@@ -0,0 +1,656 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NfcManager.java
+ * Original-Author : Trusted Logic S.A. (Jeremie Corbier)
+ * Created : 26-08-2009
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.media.MiniThumbFile;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+//import android.util.Log;
+
+/**
+ * This class provides the primary API for managing all aspects of NFC. Get an
+ * instance of this class by calling
+ * Context.getSystemService(Context.NFC_SERVICE).
+ * @hide
+ */
+public final class NfcManager {
+ /**
+ * Tag Reader Discovery mode
+ */
+ private static final int DISCOVERY_MODE_TAG_READER = 0;
+
+ /**
+ * NFC-IP1 Peer-to-Peer mode Enables the manager to act as a peer in an
+ * NFC-IP1 communication. Implementations should not assume that the
+ * controller will end up behaving as an NFC-IP1 target or initiator and
+ * should handle both cases, depending on the type of the remote peer type.
+ */
+ private static final int DISCOVERY_MODE_NFCIP1 = 1;
+
+ /**
+ * Card Emulation mode Enables the manager to act as an NFC tag. Provided
+ * that a Secure Element (an UICC for instance) is connected to the NFC
+ * controller through its SWP interface, it can be exposed to the outside
+ * NFC world and be addressed by external readers the same way they would
+ * with a tag.
+ * <p>
+ * Which Secure Element is exposed is implementation-dependent.
+ *
+ * @since AA01.04
+ */
+ private static final int DISCOVERY_MODE_CARD_EMULATION = 2;
+
+ /**
+ * Used as Parcelable extra field in
+ * {@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_TAG_DISCOVERED_ACTION}
+ * . It contains the NDEF message read from the NDEF tag discovered.
+ */
+ public static final String NDEF_MESSAGE_EXTRA = "com.trustedlogic.trustednfc.android.extra.NDEF_MESSAGE";
+
+ /**
+ * Broadcast Action: a NDEF tag has been discovered.
+ * <p>
+ * Always contains the extra field
+ * {@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_MESSAGE_EXTRA}.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_NOTIFY permission.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String NDEF_TAG_DISCOVERED_ACTION = "com.trustedlogic.trustednfc.android.action.NDEF_TAG_DISCOVERED";
+
+ /**
+ * Used as byte array extra field in
+ * {@link com.trustedlogic.trustednfc.android.NfcManager#TRANSACTION_DETECTED_ACTION}
+ * . It contains the AID of the applet concerned by the transaction.
+ */
+ public static final String AID_EXTRA = "com.trustedlogic.trustednfc.android.extra.AID";
+
+ /**
+ * Broadcast Action: a transaction with a secure element has been detected.
+ * <p>
+ * Always contains the extra field
+ * {@link com.trustedlogic.trustednfc.android.NfcManager#AID_EXTRA}
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_NOTIFY permission
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String TRANSACTION_DETECTED_ACTION = "com.trustedlogic.trustednfc.android.action.TRANSACTION_DETECTED";
+
+ /**
+ * LLCP link status: The LLCP link is activated.
+ *
+ * @since AA02.01
+ */
+ public static final int LLCP_LINK_STATE_ACTIVATED = 0;
+
+ /**
+ * LLCP link status: The LLCP link is deactivated.
+ *
+ * @since AA02.01
+ */
+ public static final int LLCP_LINK_STATE_DEACTIVATED = 1;
+
+ /**
+ * Used as int extra field in
+ * {@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_ACTION}
+ * . It contains the new state of the LLCP link.
+ */
+ public static final String LLCP_LINK_STATE_CHANGED_EXTRA = "com.trustedlogic.trustednfc.android.extra.LLCP_LINK_STATE";
+
+ /**
+ * Broadcast Action: the LLCP link state changed.
+ * <p>
+ * Always contains the extra field
+ * {@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_EXTRA}.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_LLCP permission.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String LLCP_LINK_STATE_CHANGED_ACTION = "com.trustedlogic.trustednfc.android.action.LLCP_LINK_STATE_CHANGED";
+
+ private static final String TAG = "NfcManager";
+
+ private Handler mHandler;
+
+ private INfcManager mService;
+
+ private INfcTag mNfcTagService;
+
+ private IP2pTarget mP2pTargetService;
+
+ private IP2pInitiator mP2pInitiatorService;
+
+ private ILlcpSocket mLlcpSocketService;
+
+ private ILlcpConnectionlessSocket mLlcpConnectionlessSocketService;
+
+ private ILlcpServiceSocket mLlcpServiceSocketService;
+
+ static NfcException convertErrorToNfcException(int errorCode) {
+ return convertErrorToNfcException(errorCode, null);
+ }
+
+ static NfcException convertErrorToNfcException(int errorCode, String message) {
+ if (message == null) {
+ message = "";
+ } else {
+ message = " (" + message + ")";
+ }
+
+ switch (errorCode) {
+ case ErrorCodes.ERROR_BUSY:
+ return new NfcException("Another operation is already pending" + message);
+ case ErrorCodes.ERROR_CANCELLED:
+ return new NfcException("Operation cancelled" + message);
+ case ErrorCodes.ERROR_TIMEOUT:
+ return new NfcException("Operation timed out" + message);
+ case ErrorCodes.ERROR_SOCKET_CREATION:
+ return new NfcException("Error during the creation of an Llcp socket:" + message);
+ case ErrorCodes.ERROR_SAP_USED:
+ return new NfcException("Error SAP already used:" + message);
+ case ErrorCodes.ERROR_SERVICE_NAME_USED:
+ return new NfcException("Error Service Name already used:" + message);
+ case ErrorCodes.ERROR_SOCKET_OPTIONS:
+ return new NfcException("Error Socket options:" + message);
+ case ErrorCodes.ERROR_INVALID_PARAM:
+ return new NfcException("Error Set Properties: invalid param" + message);
+ case ErrorCodes.ERROR_NFC_ON:
+ return new NfcException("Error Set Properties : NFC is ON" + message);
+ case ErrorCodes.ERROR_NOT_INITIALIZED:
+ return new NfcException("NFC is not running " + message);
+ case ErrorCodes.ERROR_SE_ALREADY_SELECTED:
+ return new NfcException("Secure Element already connected" + message);
+ case ErrorCodes.ERROR_NO_SE_CONNECTED:
+ return new NfcException("No Secure Element connected" + message);
+ case ErrorCodes.ERROR_SE_CONNECTED:
+ return new NfcException("A secure Element is already connected" + message);
+ default:
+ return new NfcException("Unkown error code " + errorCode + message);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public NfcManager(INfcManager service, Handler handler) {
+ mService = service;
+ mHandler = handler;
+ try {
+ mNfcTagService = mService.getNfcTagInterface();
+ mP2pInitiatorService = mService.getP2pInitiatorInterface();
+ mP2pTargetService = mService.getP2pTargetInterface();
+ mLlcpServiceSocketService = mService.getLlcpServiceInterface();
+ mLlcpConnectionlessSocketService = mService.getLlcpConnectionlessInterface();
+ mLlcpSocketService = mService.getLlcpInterface();
+ } catch (RemoteException e) {
+ mLlcpSocketService = null;
+ mNfcTagService = null;
+ mP2pInitiatorService = null;
+ mP2pTargetService = null;
+ mLlcpConnectionlessSocketService = null;
+ mLlcpServiceSocketService = null;
+ }
+ }
+
+ /**
+ * Return the status of the NFC feature
+ *
+ * @return mIsNfcEnabled
+ * @since AA02.01
+ */
+ public boolean isEnabled() {
+ try {
+ return mService.isEnabled();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in isEnabled(): ", e);
+ return false;
+ }
+ }
+
+ /**
+ * Enable the NFC Feature
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_ADMIN permission
+ *
+ * @throws NfcException if the enable failed
+ * @since AA02.01
+ */
+ public void enable() throws NfcException {
+ try {
+ boolean isSuccess = mService.enable();
+ if (isSuccess == false) {
+ throw new NfcException("NFC Service failed to enable");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in enable(): ", e);
+ }
+ }
+
+ /**
+ * Disable the NFC feature
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_ADMIN permission
+ *
+ * @throws NfcException if the disable failed
+ * @since AA02.01
+ */
+ public void disable() throws NfcException {
+ try {
+ boolean isSuccess = mService.disable();
+ if (isSuccess == false) {
+ throw new NfcException("NFC Service failed to disable");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in disable(): ", e);
+ }
+ }
+
+ /**
+ * Get the list of the identifiers of the Secure Elements detected
+ * by the NFC controller.
+ *
+ * @return list a list of Secure Element identifiers.
+ * @see #getSelectedSecureElement
+ * @see #selectSecureElement(int)
+ * @see #deselectSecureElement
+ * @since AA02.01
+ */
+ public int[] getSecureElementList() {
+ try {
+ return mService.getSecureElementList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getSecureElementList(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Get the identifier of the currently selected secure element.
+ *
+ * @return id identifier of the currently selected Secure Element. 0 if none.
+ * @see #getSecureElementList
+ * @see #selectSecureElement(int)
+ * @see #deselectSecureElement
+ * @since AA02.01
+ */
+ public int getSelectedSecureElement() {
+ try {
+ return mService.getSelectedSecureElement();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getSelectedSecureElement(): ", e);
+ return -1;
+ }
+ }
+
+ /**
+ * Select a specific Secure Element by its identifier.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_ADMIN permission
+ *
+ * @throws NfcException if a or this secure element is already selected
+ * @see #getSecureElementList
+ * @see #getSelectedSecureElement
+ * @see #deselectSecureElement
+ * @since AA02.01
+ */
+ public void selectSecureElement(int seId) throws NfcException {
+ try {
+ int status = mService.selectSecureElement(seId);
+ if(status != ErrorCodes.SUCCESS){
+ throw convertErrorToNfcException(status);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in selectSecureElement(): ", e);
+ }
+ }
+
+ /**
+ * Deselect the currently selected Secure Element
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_ADMIN permission
+ *
+ * @throws NfcException if no secure Element is selected
+ * @see #getSecureElementList
+ * @see #getSelectedSecureElement
+ * @see #selectSecureElement(int)
+ * @since AA02.01
+ */
+ public void deselectSecureElement() throws NfcException {
+ try {
+ int status = mService.deselectSecureElement();
+ if(status != ErrorCodes.SUCCESS){
+ throw convertErrorToNfcException(status);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in deselectSecureElement(): ", e);
+ }
+ }
+
+ /**
+ * Open a connection with a remote NFC peer
+ *
+ * This method does not return while no remote NFC peer enters the field.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_RAW permission
+ *
+ * @return P2pDevice object to be used to communicate with the detected
+ * peer.
+ * @throws IOException if the target has been lost or the connection has
+ * been closed.
+ * @throws NfcException if an open is already started
+ * @see P2pDevice
+ * @see #getOpenTimeout
+ * @see #setOpenTimeout(int)
+ * @see #cancel
+ * @since AA02.01
+ */
+ public P2pDevice openP2pConnection() throws IOException, NfcException {
+ try {
+ int handle = mService.openP2pConnection();
+ // Handle potential errors
+ if (ErrorCodes.isError(handle)) {
+ if (handle == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToNfcException(handle);
+ }
+ }
+ // Build the public NfcTag object, depending on its type
+ if (mP2pTargetService.getMode(handle) == P2pDevice.MODE_P2P_TARGET) {
+ return new P2pTarget(mP2pTargetService, handle);
+ } else {
+ return new P2pInitiator(mP2pInitiatorService, handle);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openTagConnection(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Open a connection with a tag
+ *
+ * This method does not return while no tag enters the field.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_RAW permission
+ *
+ * @return tag object to be use to communicate with the detected NfcTag.
+ * @throws IOException if the target has been lost or the connection has
+ * been closed.
+ * @throws NfcException if an open is already started
+ * @see NfcTag
+ * @see #getOpenTimeout
+ * @see #setOpenTimeout(int)
+ * @see #cancel
+ * @since AA02.01
+ */
+ public NfcTag openTagConnection() throws IOException, NfcException {
+ try {
+ int handle = mService.openTagConnection();
+ // Handle potential errors
+ if (ErrorCodes.isError(handle)) {
+ if (handle == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToNfcException(handle);
+ }
+ }
+ // Build the public NfcTag object
+ return new NfcTag(mNfcTagService, handle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openTagConnection(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Set the timeout for open requests
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_RAW permission
+ *
+ * @param timeout value of the timeout for open request
+ * @see #openP2pConnection
+ * @see #openTagConnection
+ * @see #getOpenTimeout
+ * @since AA02.01
+ */
+ public void setOpenTimeout(int timeout) {
+ try {
+ mService.setOpenTimeout(timeout);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in setOpenTimeout(): ", e);
+ }
+ }
+
+ /**
+ * Get the timeout value of open requests
+ *
+ * @return mTimeout
+ * @see #setOpenTimeout(int)
+ * @since AA02.01
+ */
+ public int getOpenTimeout() {
+ try {
+ return mService.getOpenTimeout();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getOpenTimeout(): ", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Cancel an openTagConnection or an openP2pConnection started
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_RAW permission
+ *
+ * @see #openP2pConnection
+ * @see #openTagConnection
+ * @since AA02.01
+ */
+ public void cancel() {
+ try {
+ mService.cancel();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in cancel(): ", e);
+ }
+ }
+
+ /**
+ * Creates a connectionless socket for a LLCP link and set its Service
+ * Access Point number (SAP)
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_LLCP permission
+ *
+ * @param sap Service Access Point number related to the created
+ * Connectionless socket.
+ * @return LlcpConnectionlessSocket object to be used in a LLCP
+ * Connectionless communication.
+ * @throws IOException if the socket creation failed
+ * @throws NfcException if socket ressources are insufficicent
+ * @see LlcpConnectionlessSocket
+ * @since AA02.01
+ */
+ public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int sap) throws IOException,
+ NfcException {
+
+ try {
+ int handle = mService.createLlcpConnectionlessSocket(sap);
+ // Handle potential errors
+ if (ErrorCodes.isError(handle)) {
+ if (handle == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToNfcException(handle);
+ }
+ }
+
+ // Build the public LlcpConnectionLess object
+ return new LlcpConnectionlessSocket(mLlcpConnectionlessSocketService, handle);
+
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in createLlcpConnectionlessSocket(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Creates a LlcpServiceSocket for a LLCP link, set its Service Access Point
+ * number (SAP).
+ * <p>
+ * During a LLCP communication, the LlcpServiceSocket will create LlcpSocket
+ * to communicate with incoming LLCP clients. For that, a server socket need
+ * to have some informations as a working buffer length in order to handle
+ * incoming data and some options to define the LLCP communication.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_LLCP permission
+ *
+ * @param sap
+ * @param sn Service Name of the LlcpServiceSocket
+ * @param miu Maximum Information Unit (MIU) for a LlcpSocket created by the
+ * LlcpServiceSocket
+ * @param rw Receive Window (RW) for a LlcpSocket created by the
+ * LlcpServiceSocket
+ * @param linearBufferLength size of the memory space needed to handle
+ * incoming data for every LlcpSocket created.
+ * @return LlcpServiceSocket object to be used as a LLCP Service in a
+ * connection oriented communication.
+ * @throws IOException if the socket creation failed
+ * @throws NfcException if socket ressources are insufficicent
+ * @see LlcpServiceSocket
+ * @since AA02.01
+ */
+ public LlcpServiceSocket createLlcpServiceSocket(int sap, String sn, int miu, int rw,
+ int linearBufferLength) throws IOException, NfcException {
+ try {
+ int handle = mService.createLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength);
+ // Handle potential errors
+ if (ErrorCodes.isError(handle)) {
+ if (handle == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToNfcException(handle);
+ }
+ }
+
+ // Build the public LlcpServiceSocket object
+ return new LlcpServiceSocket(mLlcpServiceSocketService, mLlcpSocketService, handle);
+
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in createLlcpServiceSocket(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Creates a LlcpSocket for a LLCP link with a specific Service Access Point
+ * number (SAP)
+ * <p>
+ * A LlcpSocket need to have a linear buffer in order to handle incoming
+ * data. This linear buffer will be used to store incoming data as a stream.
+ * Data will be readable later.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_LLCP permission
+ *
+ * @param sap Service Access Point number for the created socket
+ * @param miu Maximum Information Unit (MIU) of the communication socket
+ * @param rw Receive Window (RW) of the communication socket
+ * @param linearBufferLength size of the memory space needed to handle
+ * incoming data with this socket
+ * @throws IOException if the socket creation failed
+ * @throws NfcException if socket ressources are insufficicent
+ * @see LlcpSocket
+ * @since AA02.01
+ */
+ public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
+ throws IOException, NfcException {
+ try {
+ int handle = mService.createLlcpSocket(sap, miu, rw, linearBufferLength);
+ // Handle potential errors
+ if (ErrorCodes.isError(handle)) {
+ if (handle == ErrorCodes.ERROR_IO) {
+ throw new IOException();
+ } else {
+ throw convertErrorToNfcException(handle);
+ }
+ }
+ // Build the public LlcpSocket object
+ return new LlcpSocket(mLlcpSocketService, handle);
+
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in createLlcpSocket(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Set different parameters like the NCIP General bytes, the LLCP link
+ * parameters and all tag discovery parameters.
+ * <p class="note">
+ * <strong>Note:</strong> Requires the NFC_ADMIN permission
+ *
+ * @param param parameter to be updated with a new value
+ * @param value new value of the parameter
+ * @throws NfcException if incorrect parameters of NFC is ON
+ * @since AA02.01
+ */
+ public void setProperties(String param, String value) throws NfcException {
+ try {
+ int result = mService.setProperties(param, value);
+ // Handle potential errors
+ if (ErrorCodes.isError(result)) {
+ throw convertErrorToNfcException(result);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in setProperties(): ", e);
+ }
+ }
+
+ /**
+ * Get the value of different parameters like the NCFIP General bytes, the
+ * LLCP link parameters and all tag discovery parameters.
+ *
+ * @param param parameter to be updated
+ * @return String value of the requested parameter
+ * @throws RemoteException
+ * @since AA02.01
+ */
+ public String getProperties(String param) {
+ String value;
+ try {
+ value = mService.getProperties(param);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getProperties(): ", e);
+ return null;
+ }
+ return value;
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/NfcTag.java b/core/java/com/trustedlogic/trustednfc/android/NfcTag.java
new file mode 100644
index 0000000..798c7e4
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/NfcTag.java
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NFCTag.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ * Created : 26-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+/**
+ * This class represents tags with no known formatting. One can use the method
+ * {@link #isNdef()} to determine if the tag can store NDEF-formatted messages.
+ * <p>
+ *
+ * <pre class="prettyprint">
+ * if (tag.isNdef()) {
+ * NdefTag ndefTag = (NdefTag) tag;
+ * NdefMessage msg = ndefTag.read();
+ * }
+ * </pre>
+ *
+ * @since AA01.04
+ * @see NdefMessage
+ * @hide
+ */
+public class NfcTag {
+
+ private static final String TAG = "NfcTag";
+
+ /**
+ * The handle returned by the NFC service and used to identify the tag in
+ * every call of this class.
+ *
+ * @hide
+ */
+ protected int mHandle;
+
+ /**
+ * The entry point for tag operations.
+ *
+ * @hide
+ */
+ protected INfcTag mService;
+
+ /**
+ * Flag set when the object is closed and thus not usable any more.
+ *
+ * @hide
+ */
+ protected boolean isClosed = false;
+
+ /**
+ * Flag set when the tag is connected.
+ *
+ * @hide
+ */
+ protected boolean isConnected = false;
+
+ /**
+ * Flag set when a check NDEF is performed.
+ *
+ * @hide
+ */
+ protected boolean isNdef = false;
+
+ /**
+ * Check if tag is still opened.
+ *
+ * @return data sent by the P2pInitiator.
+ * @throws NfcException if accessing a closed target.
+ *
+ * @hide
+ */
+ public void checkState() throws NfcException {
+ if (isClosed) {
+ throw new NfcException("Tag has been closed.");
+ }
+ if (!isConnected) {
+ throw new NfcException("Tag is not connected.");
+ }
+ }
+
+ /**
+ * Internal constructor for the NfcTag class.
+ *
+ * @param service The entry point to the Nfc Service for NfcTag class.
+ * @param handle The handle returned by the NFC service and used to identify
+ * the tag in subsequent calls.
+ * @hide
+ */
+ NfcTag(INfcTag service, int handle) {
+ this.mService = service;
+ this.mHandle = handle;
+ }
+
+ /**
+ * Connects to the tag. This shall be called prior to any other operation on
+ * the tag.
+ *
+ * @throws IOException if the tag has been lost or the connection has been
+ * closed.
+ * @throws nfcException if the tag is already in connected state.
+ */
+ public void connect() throws NfcException, IOException {
+ // Check state
+ if (isClosed) {
+ throw new NfcException("Tag has been closed.");
+ }
+ if (isConnected) {
+ throw new NfcException("Already connected");
+ }
+
+ // Perform connect
+ try {
+ int result = mService.connect(mHandle);
+ if (ErrorCodes.isError(result)) {
+ if (result == ErrorCodes.ERROR_IO) {
+ throw new IOException("Failed to connect");
+ }
+ else {
+ throw NfcManager.convertErrorToNfcException(result);
+ }
+ }
+ isConnected = true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in connect(): ", e);
+ }
+ }
+
+ /**
+ * Disconnects from the tag. This must be called so that other targets can
+ * be discovered. It restarts the NFC discovery loop.
+ *
+ * @throws NfcException if the tag is already in disconnected state or not connected
+ */
+ public void close() throws NfcException {
+ // Check state
+ checkState();
+
+ try {
+ mService.close(mHandle);
+ isClosed = true;
+ isConnected = false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in close(): ", e);
+ }
+ }
+
+ /**
+ * Exchanges raw data with the tag, whatever the tag type.
+ *
+ * To exchange APDUs with a ISO14443-4-compliant tag, the data parameter
+ * must be filled with the C-APDU (CLA, INS, P1, P2 [, ...]). The returned
+ * data consists of the R-APDU ([...,] SW1, SW2).
+ *
+ * @param data data to be sent to the tag
+ * @return data sent in response by the tag
+ * @throws IOException if the tag has been lost or the connection has been
+ * closed.
+ * @throws NfcException in case of failure within the stack
+ */
+ public byte[] transceive(byte[] data) throws IOException, NfcException {
+ // Check state
+ checkState();
+
+ // Perform transceive
+ try {
+ byte[] response = mService.transceive(mHandle, data);
+ if (response == null) {
+ throw new IOException("Transceive failed");
+ }
+ return response;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in transceive(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Checks whether tag is NDEF-compliant or not.
+ *
+ * @return true if the tag is NDEF-compliant, false otherwise
+ * @throws NfcException in case an error occurred when trying to determine
+ * whether the tag is NDEF-compliant
+ */
+ public boolean isNdef() throws NfcException {
+ // Check state
+ checkState();
+
+ // Perform Check Ndef
+ try {
+ isNdef = mService.isNdef(mHandle);
+ return isNdef;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in isNdef(): ", e);
+ return false;
+ }
+ }
+
+ /**
+ * Returns target type. constants.
+ *
+ * @return tag type.
+ */
+ public String getType() {
+ try {
+ return mService.getType(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getType(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns target UID.
+ *
+ * @return tag UID.
+ */
+ public byte[] getUid() {
+ try {
+ return mService.getUid(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getType(): ", e);
+ return null;
+ }
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/P2pDevice.java b/core/java/com/trustedlogic/trustednfc/android/P2pDevice.java
new file mode 100644
index 0000000..65800f2
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/P2pDevice.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : P2PDevice.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ * Created : 26-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+/**
+ * P2pDevice is the abstract base class for all supported P2P targets the
+ * NfcManager can handle.
+ * @hide
+ */
+public abstract class P2pDevice {
+
+ /**
+ * Peer-to-Peer Target.
+ */
+ public static final short MODE_P2P_TARGET = 0x00;
+
+ /**
+ * Peer-to-Peer Initiator.
+ */
+ public static final short MODE_P2P_INITIATOR = 0x01;
+
+ /**
+ * Invalid target type.
+ */
+ public static final short MODE_INVALID = 0xff;
+
+ /**
+ * Target handle, used by native calls.
+ * @hide
+ */
+ protected int mHandle;
+
+ /**
+ * Flag set when the object is closed and thus not usable any more.
+ * @hide
+ */
+ protected boolean isClosed = false;
+
+ /**
+ * Prevent default constructor to be public.
+ * @hide
+ */
+ protected P2pDevice() {
+ }
+
+ /**
+ * Returns the remote NFC-IP1 General Bytes.
+ *
+ * @return remote general bytes
+ * @throws IOException
+ */
+ public byte[] getGeneralBytes() throws IOException {
+ // Should not be called directly (use subclasses overridden method instead)
+ return null;
+ }
+
+ /**
+ * Returns target type. The value returned can be one of the TYPE_*
+ * constants.
+ *
+ * @return target type.
+ */
+ public int getMode() {
+ // Should not be called directly (use subclasses overridden method instead)
+ return MODE_INVALID;
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/P2pInitiator.java b/core/java/com/trustedlogic/trustednfc/android/P2pInitiator.java
new file mode 100644
index 0000000..0f28ae0
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/P2pInitiator.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : P2PInitiator.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * P2pInitiator represents the initiator in an NFC-IP1 peer-to-peer
+ * communication.
+ *
+ * @see P2pTarget
+ * @since AA02.01
+ * @hide
+ */
+public class P2pInitiator extends P2pDevice {
+
+ private static final String TAG = "P2pInitiator";
+
+ /**
+ * The entry point for P2P tag operations.
+ * @hide
+ */
+ private IP2pInitiator mService;
+
+ /**
+ * Internal constructor for the P2pInitiator class.
+ *
+ * @param handle The handle returned by the NFC service and used to identify
+ * the tag in subsequent calls.
+ *
+ * @hide
+ */
+ P2pInitiator(IP2pInitiator service, int handle) {
+ this.mService = service;
+ this.mHandle = handle;
+ }
+
+ /**
+ * Receives data from a P2pInitiator.
+ *
+ * @return data sent by the P2pInitiator.
+ * @throws IOException if the target has been lost or if the connection has
+ * been closed.
+ */
+ public byte[] receive() throws IOException {
+ try {
+ byte[] result = mService.receive(mHandle);
+ if (result == null) {
+ throw new IOException("Tag has been lost");
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in receive(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Sends data to a P2pInitiator.
+ *
+ * @param data data to be sent to the P2pInitiator.
+ * @throws IOException if the target has been lost or if the connection has
+ * been closed.
+ */
+ public void send(byte[] data) throws IOException {
+ try {
+ boolean isSuccess = mService.send(mHandle, data);
+ if (!isSuccess) {
+ throw new IOException("Tag has been lost");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in send(): ", e);
+ }
+ }
+
+ @Override
+ public byte[] getGeneralBytes() {
+ try {
+ return mService.getGeneralBytes(mHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getGeneralBytes(): ", e);
+ return null;
+ }
+ }
+
+ @Override
+ public int getMode() {
+ return P2pDevice.MODE_P2P_INITIATOR;
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/P2pTarget.java b/core/java/com/trustedlogic/trustednfc/android/P2pTarget.java
new file mode 100644
index 0000000..b5e00db
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/P2pTarget.java
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : P2PTarget.java
+ * Original-Author : Trusted Logic S.A. (Daniel Tomas)
+ */
+
+package com.trustedlogic.trustednfc.android;
+
+import java.io.IOException;
+
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * P2pTarget represents the target in an NFC-IP1 peer-to-peer communication.
+ *
+ * @see P2pInitiator
+ * @since AA02.01
+ * @hide
+ */
+public class P2pTarget extends P2pDevice {
+
+ private static final String TAG = "P2pTarget";
+
+ /**
+ * The entry point for P2P tag operations.
+ * @hide
+ */
+ private IP2pTarget mService;
+
+ /**
+ * Flag set when the object is closed and thus not usable any more.
+ * @hide
+ */
+ private boolean isClosed = false;
+
+ /**
+ * Flag set when the tag is connected.
+ * @hide
+ */
+ private boolean isConnected = false;
+
+ /**
+ * Check if tag is still opened.
+ *
+ * @return data sent by the P2pInitiator.
+ * @throws NfcException if accessing a closed target.
+ *
+ * @hide
+ */
+ public void checkState() throws NfcException {
+ if(isClosed) {
+ throw new NfcException("Tag has been closed.");
+ }
+ }
+
+ /**
+ * Internal constructor for the P2pTarget class.
+ *
+ * @param handle The handle returned by the NFC service and used to identify
+ * the tag in subsequent calls.
+ *
+ * @hide
+ */
+ P2pTarget(IP2pTarget service, int handle) {
+ this.mService = service;
+ this.mHandle = handle;
+ }
+
+ /**
+ * Connects to the P2pTarget. This shall be called prior to any other
+ * operation on the P2pTarget.
+ *
+ * @throws NfcException
+ */
+ public void connect() throws NfcException {
+ // Check state
+ checkState();
+ if (isConnected) {
+ throw new NfcException("Already connected");
+ }
+
+ // Perform connect
+ try {
+ int result = mService.connect(mHandle);
+ if (ErrorCodes.isError(result)) {
+ if (result == ErrorCodes.ERROR_IO) {
+ throw new NfcException("Failed to connect");
+ }
+ else {
+ throw NfcManager.convertErrorToNfcException(result);
+ }
+ }
+ isConnected = true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in connect(): ", e);
+ }
+ }
+
+ /**
+ * Disconnects from the P2p Target. This must be called so that other
+ * targets can be discovered. It restarts the NFC discovery loop.
+ *
+ * @throws NFCException
+ */
+ public void disconnect() throws NfcException {
+ checkState();
+ try {
+ mService.disconnect(mHandle);
+ isConnected = true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in disconnect(): ", e);
+ }
+ }
+
+ /**
+ * Exchanges raw data with the P2pTarget.
+ *
+ * @param data data to be sent to the P2pTarget
+ * @return data sent in response by the P2pTarget
+ * @throws IOException if the target has been lost or the connection has
+ * been closed.
+ * @throws NfcException in case of failure within the stack
+ */
+ public byte[] transceive(byte[] data) throws IOException, NfcException {
+ // Check state
+ checkState();
+
+ // Perform transceive
+ try {
+ byte[] response = mService.transceive(mHandle, data);
+ if (response == null) {
+ throw new IOException("Transceive failed");
+ }
+ return response;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in transceive(): ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Get the General bytes of the connected P2P Target
+ *
+ * @return general bytes of the connected P2P Target
+ * @throws IOException if the target in not in connected state
+ */
+ public byte[] getGeneralBytes() throws IOException {
+ try {
+ if(isConnected){
+ return mService.getGeneralBytes(mHandle);
+ }else{
+ throw new IOException("Target not in connected state");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getGeneralBytes(): ", e);
+ return null;
+ }
+ }
+
+ @Override
+ public int getMode() {
+ return P2pDevice.MODE_P2P_TARGET;
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/ErrorCodes.java b/core/java/com/trustedlogic/trustednfc/android/internal/ErrorCodes.java
new file mode 100644
index 0000000..ca3b7e0
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/ErrorCodes.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : ErrorCodes.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 26-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+/**
+ * This class defines all the error codes that can be returned by the service
+ * and producing an exception on the application level. These are needed since
+ * binders does not support exceptions.
+ *
+ * @hide
+ */
+public class ErrorCodes {
+
+ public static boolean isError(int code) {
+ if (code < 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static final int SUCCESS = 0;
+
+ public static final int ERROR_IO = -1;
+
+ public static final int ERROR_CANCELLED = -2;
+
+ public static final int ERROR_TIMEOUT = -3;
+
+ public static final int ERROR_BUSY = -4;
+
+ public static final int ERROR_CONNECT = -5;
+
+ public static final int ERROR_DISCONNECT = -5;
+
+ public static final int ERROR_READ = -6;
+
+ public static final int ERROR_WRITE = -7;
+
+ public static final int ERROR_INVALID_PARAM = -8;
+
+ public static final int ERROR_INSUFFICIENT_RESOURCES = -9;
+
+ public static final int ERROR_SOCKET_CREATION = -10;
+
+ public static final int ERROR_SOCKET_NOT_CONNECTED = -11;
+
+ public static final int ERROR_BUFFER_TO_SMALL = -12;
+
+ public static final int ERROR_SAP_USED = -13;
+
+ public static final int ERROR_SERVICE_NAME_USED = -14;
+
+ public static final int ERROR_SOCKET_OPTIONS = -15;
+
+ public static final int ERROR_NFC_ON = -16;
+
+ public static final int ERROR_NOT_INITIALIZED = -17;
+
+ public static final int ERROR_SE_ALREADY_SELECTED = -18;
+
+ public static final int ERROR_SE_CONNECTED = -19;
+
+ public static final int ERROR_NO_SE_CONNECTED = -20;
+
+
+
+
+
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpConnectionlessSocket.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpConnectionlessSocket.java
new file mode 100644
index 0000000..ccfbeb4
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpConnectionlessSocket.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NativeLlcpConnectionLessSocket.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+import com.trustedlogic.trustednfc.android.LlcpPacket;
+
+/**
+ * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used
+ * in a connectionless communication
+ *
+ * @since AA02.01
+ * {@hide}
+ */
+
+public class NativeLlcpConnectionlessSocket {
+
+ private int mHandle;
+
+ private int mSap;
+
+ private int mLinkMiu;
+
+ public NativeLlcpConnectionlessSocket(){;
+ }
+
+ public NativeLlcpConnectionlessSocket(int sap){
+ mSap = sap;
+ }
+
+ public native boolean doSendTo(int sap, byte[] data);
+
+ public native LlcpPacket doReceiveFrom(int linkMiu);
+
+ public native boolean doClose();
+
+ public int getLinkMiu(){
+ return mLinkMiu;
+ }
+
+ public int getSap(){
+ return mSap;
+ }
+
+ public int getHandle(){
+ return mHandle;
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpServiceSocket.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpServiceSocket.java
new file mode 100644
index 0000000..a01f135
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpServiceSocket.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NativeLlcpServerSocket.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+/**
+ * LlcpServiceSocket represents a LLCP Service to be used in a
+ * Connection-oriented communication
+ * {@hide}
+ */
+
+public class NativeLlcpServiceSocket {
+
+ private int mHandle;
+
+ private int mLocalMiu;
+
+ private int mLocalRw;
+
+ private int mLocalLinearBufferLength;
+
+ private int mSap;
+
+ private int mTimeout;
+
+ private String mServiceName;
+
+ public NativeLlcpServiceSocket(){
+
+ }
+
+ public NativeLlcpServiceSocket(String serviceName){
+ mServiceName = serviceName;
+ }
+
+ public native NativeLlcpSocket doAccept(int timeout, int miu, int rw, int linearBufferLength);
+
+ public native boolean doClose();
+
+ public int getHandle(){
+ return mHandle;
+ }
+
+ public void setAcceptTimeout(int timeout){
+ mTimeout = timeout;
+ }
+
+ public int getAcceptTimeout(){
+ return mTimeout;
+ }
+
+ public int getRw(){
+ return mLocalRw;
+ }
+
+ public int getMiu(){
+ return mLocalMiu;
+ }
+
+ public int getLinearBufferLength(){
+ return mLocalLinearBufferLength;
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpSocket.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpSocket.java
new file mode 100644
index 0000000..077c5e0
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpSocket.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.
+ */
+
+/**
+ * File : NativeLlcpClientSocket.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+/**
+ * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a
+ * connection-oriented communication
+ * {@hide}
+ */
+
+public class NativeLlcpSocket {
+
+ private int mHandle;
+
+ private int mSap;
+
+ private int mLocalMiu;
+
+ private int mLocalRw;
+
+ private int mTimeout;
+
+ public NativeLlcpSocket(){
+
+ }
+
+ public NativeLlcpSocket(int sap, int miu, int rw){
+ mSap = sap;
+ mLocalMiu = miu;
+ mLocalRw = rw;
+ }
+
+ public native boolean doConnect(int nSap, int timeout);
+
+ public native boolean doConnectBy(String sn, int timeout);
+
+ public native boolean doClose();
+
+ public native boolean doSend(byte[] data);
+
+ public native int doReceive(byte[] recvBuff);
+
+ public native int doGetRemoteSocketMiu();
+
+ public native int doGetRemoteSocketRw();
+
+
+
+ public void setConnectTimeout(int timeout){
+ mTimeout = timeout;
+ }
+
+ public int getConnectTimeout(){
+ return mTimeout;
+ }
+
+ public int getSap(){
+ return mSap;
+ }
+
+ public int getMiu(){
+ return mLocalMiu;
+ }
+
+ public int getRw(){
+ return mLocalRw;
+ }
+
+ public int getHandle(){
+ return mHandle;
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeNdefTag.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNdefTag.java
new file mode 100644
index 0000000..d1e64a6
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNdefTag.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NativeNdefTag.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+/**
+ * Native interface to the NDEF tag functions
+ *
+ * {@hide}
+ */
+public class NativeNdefTag {
+ private int mHandle;
+
+ public native byte[] doRead();
+
+ public native boolean doWrite(byte[] buf);
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcManager.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcManager.java
new file mode 100644
index 0000000..2f5a0f0
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcManager.java
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NativeNfcManager.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import com.trustedlogic.trustednfc.android.NfcManager;
+import com.trustedlogic.trustednfc.android.NdefMessage;
+import com.trustedlogic.trustednfc.android.NfcTag;
+
+/**
+ * Native interface to the NFC Manager functions {@hide}
+ */
+public class NativeNfcManager {
+
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA = "com.trustedlogic.trustednfc.android.extra.INTERNAL_LLCP_LINK_STATE";
+
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION = "com.trustedlogic.trustednfc.android.action.INTERNAL_LLCP_LINK_STATE_CHANGED";
+
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.trustedlogic.trustednfc.android.action.INTERNAL_TARGET_DESELECTED";
+
+ /* Native structure */
+ private int mNative;
+
+ private Context mContext;
+
+ private Handler mNfcHandler;
+
+ private static final String TAG = "NativeNfcManager";
+
+ private static final int MSG_NDEF_TAG = 0;
+
+ private static final int MSG_CARD_EMULATION = 1;
+
+ private static final int MSG_LLCP_LINK_ACTIVATION = 2;
+
+ private static final int MSG_LLCP_LINK_DEACTIVATED = 3;
+
+ private static final int MSG_TARGET_DESELECTED = 4;
+
+ public NativeNfcManager(Context context) {
+ mNfcHandler = new NfcHandler();
+ mContext = context;
+ }
+
+ /**
+ * Initializes Native structure
+ */
+ public native boolean initializeNativeStructure();
+
+ /**
+ * Initializes NFC stack.
+ */
+ public native boolean initialize();
+
+ /**
+ * Deinitializes NFC stack.
+ */
+ public native boolean deinitialize();
+
+ /**
+ * Enable discory for the NdefMessage and Transaction notification
+ */
+ public native void enableDiscovery(int mode);
+
+ /**
+ * Disables an NFCManager mode of operation. Allows to disable tag reader,
+ * peer to peer initiator or target modes.
+ *
+ * @param mode discovery mode to enable. Must be one of the provided
+ * NFCManager.DISCOVERY_MODE_* constants.
+ */
+ public native void disableDiscoveryMode(int mode);
+
+ public native int[] doGetSecureElementList();
+
+ public native void doSelectSecureElement(int seID);
+
+ public native void doDeselectSecureElement(int seID);
+
+ public native NativeP2pDevice doOpenP2pConnection(int timeout);
+
+ public native NativeNfcTag doOpenTagConnection(int timeout);
+
+ public native int doGetLastError();
+
+ public native void doSetProperties(int param, int value);
+
+ public native void doCancel();
+
+ public native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap);
+
+ public native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
+ int rw, int linearBufferLength);
+
+ public native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
+ int linearBufferLength);
+
+ public native boolean doCheckLlcp();
+
+ public native boolean doActivateLlcp();
+
+ private class NfcHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+
+ try {
+ switch (msg.what) {
+ case MSG_NDEF_TAG:
+ Log.d(TAG, "Checking for NDEF tag message");
+ NativeNfcTag tag = (NativeNfcTag) msg.obj;
+ if (tag.doConnect()) {
+ if (tag.checkNDEF()) {
+ byte[] buff = tag.doRead();
+ if (buff != null) {
+ NdefMessage msgNdef = new NdefMessage(buff);
+ if (msgNdef != null) {
+ /* Send broadcast ordered */
+ Intent NdefMessageIntent = new Intent();
+ NdefMessageIntent
+ .setAction(NfcManager.NDEF_TAG_DISCOVERED_ACTION);
+ NdefMessageIntent.putExtra(NfcManager.NDEF_MESSAGE_EXTRA,
+ msgNdef);
+ Log.d(TAG, "NDEF message found, broadcasting to applications");
+ mContext.sendOrderedBroadcast(NdefMessageIntent,
+ android.Manifest.permission.NFC_NOTIFY);
+ /* Disconnect tag */
+ tag.doAsyncDisconnect();
+ }
+ } else {
+ Log.w(TAG, "Unable to read NDEF message (tag empty or not well formated)");
+ /* Disconnect tag */
+ tag.doAsyncDisconnect();
+ }
+ } else {
+ Log.d(TAG, "Tag is *not* NDEF compliant");
+ /* Disconnect tag */
+ tag.doAsyncDisconnect();
+ }
+ } else {
+ /* Disconnect tag */
+ tag.doAsyncDisconnect();
+ }
+ break;
+ case MSG_CARD_EMULATION:
+ Log.d(TAG, "Card Emulation message");
+ byte[] aid = (byte[]) msg.obj;
+ /* Send broadcast ordered */
+ Intent TransactionIntent = new Intent();
+ TransactionIntent.setAction(NfcManager.TRANSACTION_DETECTED_ACTION);
+ TransactionIntent.putExtra(NfcManager.AID_EXTRA, aid);
+ Log.d(TAG, "Broadcasting Card Emulation event");
+ mContext.sendOrderedBroadcast(TransactionIntent,
+ android.Manifest.permission.NFC_NOTIFY);
+ break;
+
+ case MSG_LLCP_LINK_ACTIVATION:
+ NativeP2pDevice device = (NativeP2pDevice) msg.obj;
+
+ Log.d(TAG, "LLCP Activation message");
+
+ if (device.getMode() == NativeP2pDevice.MODE_P2P_TARGET) {
+ if (device.doConnect()) {
+ /* Check Llcp compliancy */
+ if (doCheckLlcp()) {
+ /* Activate Llcp Link */
+ if (doActivateLlcp()) {
+ Log.d(TAG, "Initiator Activate LLCP OK");
+ /* Broadcast Intent Link LLCP activated */
+ Intent LlcpLinkIntent = new Intent();
+ LlcpLinkIntent
+ .setAction(INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION);
+ LlcpLinkIntent.putExtra(
+ INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA,
+ NfcManager.LLCP_LINK_STATE_ACTIVATED);
+ Log.d(TAG, "Broadcasting internal LLCP activation");
+ mContext.sendBroadcast(LlcpLinkIntent);
+ }
+
+ } else {
+ device.doDisconnect();
+ }
+
+ }
+
+ } else if (device.getMode() == NativeP2pDevice.MODE_P2P_INITIATOR) {
+ /* Check Llcp compliancy */
+ if (doCheckLlcp()) {
+ /* Activate Llcp Link */
+ if (doActivateLlcp()) {
+ Log.d(TAG, "Target Activate LLCP OK");
+ /* Broadcast Intent Link LLCP activated */
+ Intent LlcpLinkIntent = new Intent();
+ LlcpLinkIntent
+ .setAction(INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION);
+ LlcpLinkIntent.putExtra(INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA,
+ NfcManager.LLCP_LINK_STATE_ACTIVATED);
+ Log.d(TAG, "Broadcasting internal LLCP activation");
+ mContext.sendBroadcast(LlcpLinkIntent);
+ }
+ }
+ }
+ break;
+
+ case MSG_LLCP_LINK_DEACTIVATED:
+ /* Broadcast Intent Link LLCP activated */
+ Log.d(TAG, "LLCP Link Deactivated message");
+ Intent LlcpLinkIntent = new Intent();
+ LlcpLinkIntent.setAction(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION);
+ LlcpLinkIntent.putExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA,
+ NfcManager.LLCP_LINK_STATE_DEACTIVATED);
+ Log.d(TAG, "Broadcasting LLCP deactivation");
+ mContext.sendOrderedBroadcast(LlcpLinkIntent,
+ android.Manifest.permission.NFC_LLCP);
+ break;
+
+ case MSG_TARGET_DESELECTED:
+ /* Broadcast Intent Target Deselected */
+ Log.d(TAG, "Target Deselected");
+ Intent TargetDeselectedIntent = new Intent();
+ TargetDeselectedIntent.setAction(INTERNAL_TARGET_DESELECTED_ACTION);
+ Log.d(TAG, "Broadcasting Intent");
+ mContext.sendOrderedBroadcast(TargetDeselectedIntent,
+ android.Manifest.permission.NFC_LLCP);
+ break;
+
+ default:
+ Log.e(TAG, "Unknown message received");
+ break;
+ }
+ } catch (Exception e) {
+ // Log, don't crash!
+ Log.e(TAG, "Exception in NfcHandler.handleMessage:", e);
+ }
+ }
+ };
+
+ /**
+ * Notifies Ndef Message
+ */
+ private void notifyNdefMessageListeners(NativeNfcTag tag) {
+ Message msg = mNfcHandler.obtainMessage();
+
+ msg.what = MSG_NDEF_TAG;
+ msg.obj = tag;
+
+ mNfcHandler.sendMessage(msg);
+ }
+
+ /**
+ * Notifies transaction
+ */
+ private void notifyTargetDeselected() {
+ Message msg = mNfcHandler.obtainMessage();
+
+ msg.what = MSG_TARGET_DESELECTED;
+
+ mNfcHandler.sendMessage(msg);
+ }
+
+ /**
+ * Notifies transaction
+ */
+ private void notifyTransactionListeners(byte[] aid) {
+ Message msg = mNfcHandler.obtainMessage();
+
+ msg.what = MSG_CARD_EMULATION;
+ msg.obj = aid;
+
+ mNfcHandler.sendMessage(msg);
+ }
+
+ /**
+ * Notifies P2P Device detected, to activate LLCP link
+ */
+ private void notifyLlcpLinkActivation(NativeP2pDevice device) {
+ Message msg = mNfcHandler.obtainMessage();
+
+ msg.what = MSG_LLCP_LINK_ACTIVATION;
+ msg.obj = device;
+
+ mNfcHandler.sendMessage(msg);
+ }
+
+ /**
+ * Notifies P2P Device detected, to activate LLCP link
+ */
+ private void notifyLlcpLinkDeactivated() {
+ Message msg = mNfcHandler.obtainMessage();
+
+ msg.what = MSG_LLCP_LINK_DEACTIVATED;
+
+ mNfcHandler.sendMessage(msg);
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcTag.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcTag.java
new file mode 100644
index 0000000..b92783d
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcTag.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.
+ */
+
+/**
+ * File : NativeNfcTag.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+/**
+ * Native interface to the NFC tag functions
+ *
+ * {@hide}
+ */
+public class NativeNfcTag {
+ private int mHandle;
+
+ private String mType;
+
+ private byte[] mUid;
+
+ public native boolean doConnect();
+
+ public native boolean doDisconnect();
+
+ public native void doAsyncDisconnect();
+
+ public native byte[] doTransceive(byte[] data);
+
+ public native boolean checkNDEF();
+
+ public native byte[] doRead();
+
+ public native boolean doWrite(byte[] buf);
+
+ public int getHandle() {
+ return mHandle;
+ }
+
+ public String getType() {
+ return mType;
+ }
+
+ public byte[] getUid() {
+ return mUid;
+ }
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeP2pDevice.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeP2pDevice.java
new file mode 100644
index 0000000..75d25ba
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeP2pDevice.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/**
+ * File : NativeP2pDevice.java
+ * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau)
+ * Created : 18-02-2010
+ */
+
+package com.trustedlogic.trustednfc.android.internal;
+
+/**
+ * Native interface to the P2P Initiator functions
+ *
+ * {@hide}
+ */
+public class NativeP2pDevice {
+
+ /**
+ * Peer-to-Peer Target.
+ */
+ public static final short MODE_P2P_TARGET = 0x00;
+
+ /**
+ * Peer-to-Peer Initiator.
+ */
+ public static final short MODE_P2P_INITIATOR = 0x01;
+
+ /**
+ * Invalid target type.
+ */
+ public static final short MODE_INVALID = 0xff;
+
+ private int mHandle;
+
+ private int mMode;
+
+ private byte[] mGeneralBytes;
+
+ public native byte[] doReceive();
+
+ public native boolean doSend(byte[] data);
+
+ public native boolean doConnect();
+
+ public native boolean doDisconnect();
+
+ public native byte[] doTransceive(byte[] data);
+
+ public int getHandle() {
+ return mHandle;
+ }
+
+ public int getMode() {
+ return mMode;
+ }
+
+ public byte[] getGeneralBytes() {
+ return mGeneralBytes;
+ }
+
+}
diff --git a/core/java/com/trustedlogic/trustednfc/android/package.html b/core/java/com/trustedlogic/trustednfc/android/package.html
new file mode 100644
index 0000000..0c0b605
--- /dev/null
+++ b/core/java/com/trustedlogic/trustednfc/android/package.html
@@ -0,0 +1,473 @@
+<html>
+<body>
+
+<p>Provides classes that manage the NFC functionality.</p>
+
+<p>The NFC functionality is related to Near Field Communication.</p>
+
+<p>The NFC APIs let applications:</p>
+<ul>
+ <li>Scan for remote NFC targets (NFC Tag or NFC Peer)</li>
+ <li>Transfer raw data to and from remote NFC targets (NFC Tags or NFC Peer)</li>
+ <li>Read/Write NDEF data from/to remote NFC targets (NFC Tags)</li>
+ <li>Establish LLCP connection with a remote NFC target (NFC Peer with LLCP support)</li>
+ <li>Exchange data with a remote NFC target through LLCP services (NFC Peer with LLCP support)</li>
+ <li>Be notified of transactions on the local Secure Element by an external NFC reader</li>
+</ul>
+
+
+<h1>Setting Up NFC</h1>
+
+<p>
+Before an application can use the NFC feature, it needs to check if NFC is
+supported on the device by getting an instance of the
+{@link com.trustedlogic.trustednfc.android.NfcManager} class.
+</p>
+
+<pre>
+ NfcManager mNfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE);
+ if (mNfcManager == null) {
+ // Device does not support NFC
+ }
+</pre>
+
+<p>
+An application can ensure that NFC is enabled.
+If not, an application with the needed permission can request that NFC be
+enabled.
+</p>
+
+<pre>
+ if (!mNfcManager.isEnabled) {
+ // NFC is currently disabled.
+ // Enable NFC.
+ mNfcManager.enable();
+ }
+</pre>
+
+<p>
+Before using the card emulation mode, an application can ensure that a secure
+element is selected ({@link com.trustedlogic.trustednfc.android.NfcManager#getSelectedSecureElement}).
+If not, an application with the needed permission can recover the list of
+available secure elements on the device
+({@link com.trustedlogic.trustednfc.android.NfcManager#getSecureElementList}) and select one
+({@link com.trustedlogic.trustednfc.android.NfcManager#selectSecureElement}).
+</p>
+
+<p>
+Before using the NFC feature, an application can configure the NFC device by
+calling {@link com.trustedlogic.trustednfc.android.NfcManager#setProperties}. This function allows:
+</p>
+<ul>
+ <li>Enabling/disabling the NFC device capabilities (RF types, baudrates,
+ NFCIP-1 mode and role...)</li>
+ <li>Settings the NFCIP-1 general bytes and the LLCP link parameters</li>
+</ul>
+<p>
+The setting properties can be customized according to the Device capabilities.
+The next table give the minimal set of properties supported by the Device.
+Depending on the implementation, the table may be completed.
+</p>
+<table>
+ <TR><TH> Property Name </TH><TH> Property Values </TH></TR>
+ <TR><TD> discovery.felica </TD><TD> <b>true</b>|false </TD></TR>
+ <TR><TD> discovery.iso14443A </TD><TD> <b>true</b>|false </TD></TR>
+ <TR><TD> discovery.iso14443B </TD><TD> <b>true</b>|false </TD></TR>
+ <TR><TD> discovery.iso15693 </TD><TD> <b>true</b>|false </TD></TR>
+ <TR><TD> discovery.nfcip </TD><TD> <b>true</b>|false </TD></TR>
+ <TR><TD> nfcip.baudrate </TD><TD> 106|212|424 </TD></TR>
+ <TR><TD> nfcip.generalbytes </TD><TD> </TD></TR>
+ <TR><TD> nfcip.mode </TD><TD> active|passive|<b>all</b> </TD></TR>
+ <TR><TD> nfcip.role </TD><TD> initiator|target|<b>both</b> </TD></TR>
+ <TR><TD> llcp.lto </TD><TD> <b>150</b> (0 to 255) </TD></TR>
+ <TR><TD> llcp.opt </TD><TD> <b>0</b> (0 to 3) </TD></TR>
+ <TR><TD> llcp.miu </TD><TD> <b>128</b> (128 to 2176) </TD></TR>
+ <TR><TD> llcp.wks </TD><TD> <b>1</b> (0 to 15) </TD></TR>
+</table>
+<p>(default values in bold)</p>
+
+
+<h1>NFC Permissions</h1>
+
+<p>
+To change the NFC service settings such as enabling the NFC targets
+discovery or activating the secure element, an application must declare the
+NFC_ADMIN permission.
+</p>
+<p>
+To perform NFC raw communication with a remote NFC target in
+Reader/Write Mode or Peer-to-Peer Mode, an application must declare the NFC_RAW
+permission.
+</p>
+<p>
+To receive NDEF message or Secure Element intents, an application must declare
+the NFC_NOTIFY permission.
+</p>
+<p>
+To receive the LLCP link intent and perform an LLCP communication with a remote NFC target, an application must
+declare the NFC_LLCP permission.
+</p>
+
+
+<h1>NFC Usage</h1>
+
+<p>
+The following code samples illustrate the APIs usage regarding the NFC service
+use cases.
+</p>
+
+<h2>Reader/Writer Mode NDEF message notification</h2>
+
+<p>
+This code sample illustrates the NDEF message notification through an Intent declared in the manifest and a receiver implemented in the application.
+</p>
+<p>Main involved classes/methods:</p>
+
+<p>Manifest Example:</p>
+<pre>
+ &lt;receiver android:name=".NfcReaderDemoReceiver">
+ &lt;intent-filter>
+ &lt;action android:name= "com.trustedlogic.trustednfc.android.action.NDEF_TAG_DISCOVERED"/>
+ &lt;/intent-filter>
+ &lt;/receiver>
+</pre>
+
+<p>Receiver Example:</p>
+<ul>
+ <li>{@link com.trustedlogic.trustednfc.android.NdefMessage}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_TAG_DISCOVERED_ACTION}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_MESSAGE_EXTRA}</li>
+</ul>
+<pre>
+public class NdefMessageReceiverSample extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(NfcManager.NDEF_TAG_DISCOVERERD_ACTION)) {
+ NdefMessage msg = intent.getParcelableExtra(NfcManager.NDEF_MESSAGE_EXTRA);
+
+ /* Manage the NdefMessage received */
+ }
+</pre>
+
+<h2>Reader/Writer Mode raw exchange</h2>
+
+<p>
+This code sample illustrates raw exchanges with a NFC target in Reader/Writer
+mode.
+</p>
+<p>Main involved classes/methods:</p>
+<ul>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#openTagConnection}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcTag}</li>
+</ul>
+
+<pre>
+public class TagReaderSample {
+
+ /** The NFC manager to access NFC features */
+ private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE);
+
+ private void runTagReader() {
+ NfcTag tag = null;
+ String type;
+ byte[] cmd = { 0x01, 0x02, 0x03 };
+ byte[] res;
+
+ while (true) {
+ try {
+ Log.i("NFC example", "Please wave in front of the tag");
+ // Open a connection on next available tag
+ try {
+ tag = manager.openTagConnection();
+ } catch (NfcException e) {
+ // TODO: Handle open failure
+ }
+
+ // Look for a mifare 4k
+ type = tag.getType();
+ if (type.equals("Mifare4K")) {
+ Log.i("NFC example", "Tag detected");
+ tag.connect();
+ // Ready to communicate, we can send transceive !
+ res = tag.transceive(cmd);
+ } else {
+ Log.i("NFC example", "Unknown tag");
+ }
+ } catch (IOException e) {
+ // TODO: Handle broken connection
+ } finally {
+ if (tag != null) {
+ tag.close();
+ }
+ }
+ }
+ }
+}
+</pre>
+
+<h2>Peer-to-Peer Mode raw exchange</h2>
+
+<p>
+This code sample illustrates raw exchanges with a NFC target in Peer-to-Peer
+mode.
+</p>
+<p>Main involved classes/methods:</p>
+<ul>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#openP2pConnection}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.P2pDevice}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.P2pInitiator}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.P2pTarget}</li>
+</ul>
+
+<pre>
+public class P2pSample {
+
+ /** The NFC manager to access NFC features */
+ private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE);
+
+ private void runP2p() {
+ P2pDevice deviceP2p;
+ P2pInitiator initiator;
+ P2pTarget target;
+ byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ byte[] echo = new byte[data.length * 10];
+
+ try {
+ deviceP2p = manager.openP2pConnection();
+
+ if (deviceP2p.getMode() == P2pDevice.MODE_P2P_INITIATOR) {
+ target = new P2pTarget(deviceP2p);
+ // Connect to the detected P2P target
+ target.connect();
+ // send data to the target
+ target.transceive(data);
+ // disconnect the connected target
+ target.disconnect();
+ } else if (deviceP2p.getMode() == P2pDevice.MODE_P2P_TARGET) {
+ initiator = new P2pInitiator(deviceP2p);
+ //target in receive state
+ echo = initiator.receive();
+ // send back the data received
+ initiator.send(echo);
+ }
+ } catch (IOException e0) {
+
+ } catch (NfcException e1) {
+
+ }
+ }
+}
+</pre>
+
+<h2>Peer-to-Peer Mode LLCP exchange</h2>
+
+<p>
+This code sample illustrates how to get LLCP link state notification with the declaration of a Receiver in the manifest of the application and the implementation
+of the receiver in the application.
+</p>
+<p>Manifest Example:</p>
+<pre>
+ &lt;receiver android:name=".LlcpModeReceiverSample">
+ &lt;intent-filter>
+ &lt;action android:name= "com.trustedlogic.trustednfc.android.action.LLCP_LINK_STATE_CHANGED"/>
+ &lt;/intent-filter>
+ &lt;/receiver>
+</pre>
+
+<p>Receiver Example:</p>
+<ul>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_ACTION}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_EXTRA}</li>
+</ul>
+<pre>
+public class LlcpModeReceiverSample extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+
+ if (intent.getAction().equals(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION)){
+ byte[] aid = intent.getByteArrayExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA);
+ /* Create an LLCP service or client and start an LLCP communication */
+ }
+ }
+</pre>
+
+
+<p>
+This code samples illustrate LLCP exchanges with a NFC Peer.
+</p>
+<p>Main involved classes/methods:</p>
+<ul>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpSocket}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpConnectionlessSocket}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpServiceSocket}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.LlcpSocket}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.LlcpConnectionlessSocket}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.LlcpPacket}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.LlcpServiceSocket}</li>
+</ul>
+
+<pre>
+public class LlcpServerSample {
+
+ /** The NFC manager to access NFC features */
+ private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE);
+
+ private void runLlcpClient() {
+ LlcpSocket sock;
+ byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ byte[] echo = new byte[data.length * 10];
+ int length = 0;
+
+ sock = manager.createLlcpSocket((short) 128, (byte) 2, 1024);
+
+ // set a timeout in ms for connect request
+ sock.setConnectTimeout(10);
+
+ try {
+ // Connect to remote service
+ // NOTE: could be sock.connect("com.trusted-logic.tnfc.testapp");
+ sock.connect((byte) 0x10);
+
+ // Send data
+ for (int i = 0; i < 10; i++) {
+ sock.send(data);
+ }
+
+ // Receive echo
+ while (length < 10 * data.length) {
+ length += sock.receive(echo);
+ }
+
+ } catch (IOException e) {
+ // TODO: Handle broken connection broken (link down, remote closure
+ // or connect rejected) or Timeout expired
+ }
+ }
+}
+</pre>
+
+<pre>
+public class LlcpClientSample {
+
+ /** The NFC manager to access NFC features */
+ private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE);
+
+ private void runLlcpClient() {
+ LlcpSocket sock;
+ byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ byte[] echo = new byte[data.length * 10];
+ int length = 0;
+
+ sock = manager.createLlcpSocket((short) 128, (byte) 2, 1024);
+ try {
+ // Connect to remote service
+ // NOTE: could be sock.connect("com.trusted-logic.tnfc.testapp");
+ sock.connect((byte) 0x10);
+
+ // Send data
+ for (int i = 0; i < 10; i++) {
+ sock.send(data);
+ }
+
+ // Receive echo
+ while (length < 10 * data.length) {
+ length += sock.receive(echo);
+ }
+
+ } catch (IOException e) {
+ // TODO: Handle broken connection broken (link down, remote closure
+ // or connect rejected)
+ }
+ }
+}
+</pre>
+
+<h2>Card Emulation Mode transaction notification</h2>
+
+<p>
+This code sample illustrates how to get the card emulation notification with the declaration of a Receiver in the manifest of the application and the implementation
+of the receiver in the application.
+</p>
+<p>Manifest Example:</p>
+<pre>
+ &lt;receiver android:name=".NfcReaderDemoReceiver">
+ &lt;intent-filter>
+ &lt;action android:name= "com.trustedlogic.trustednfc.android.action.TRANSACTION_DETECTED"/>
+ &lt;/intent-filter>
+ &lt;/receiver>
+</pre>
+
+<p>Receiver Example:</p>
+<ul>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#TRANSACTION_DETECTED_ACTION}</li>
+ <li>{@link com.trustedlogic.trustednfc.android.NfcManager#AID_EXTRA}</li>
+</ul>
+<pre>
+public class CardEmulationReceiverSample extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+
+ if (intent.getAction().equals(NfcManager.TRANSACTION_DETECTED_ACTION)){
+ byte[] aid = intent.getByteArrayExtra(NfcManager.AID_EXTRA);
+ /* Manage the AID: */
+ /* For example start an activity related to this AID value or display a popup with the AID */
+ }
+ }
+</pre>
+
+
+
+<h1>Multiple Applications rules</h1>
+
+<p>
+Several LLCP sockets can be created by a single application or by multiple
+applications by calling {@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpSocket},
+{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpConnectionlessSocket} or
+{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpServiceSocket}, provided the local SAP
+numbers are differents.
+</p>
+
+<p>
+Only one application can open a raw connection by calling
+{@link com.trustedlogic.trustednfc.android.NfcManager#openTagConnection} or
+{@link com.trustedlogic.trustednfc.android.NfcManager#openP2pConnection}.
+While this application has not closed or cancelled its connection, any other
+application that attempts to open another raw connection will raise an
+exception.
+During an open connnection, the card emulation mode is always enabled and
+applications are able to receive card emulation intents.
+</p>
+
+<p>
+When an application opens a tag connection by calling
+{@link com.trustedlogic.trustednfc.android.NfcManager#openTagConnection}, this operation is exclusive, no NDEF message intent are
+broadcast while the connection is not closed or canceled.
+</p>
+
+<p>
+When an application opens a peer-to-peer connection by calling
+{@link com.trustedlogic.trustednfc.android.NfcManager#openP2pConnection}, this operation is exclusive, no LLCP intent are broadcast and LLCP sockets are
+disabled while the connection is not closed or canceled.
+</p>
+
+
+<h1>NFC Tag types</h1>
+
+<p>
+The {@link com.trustedlogic.trustednfc.android.NfcTag} type returned by
+{@link com.trustedlogic.trustednfc.android.NfcTag#getType} indicates the set of
+commands supported by the tag. These commands can be used in
+{@link com.trustedlogic.trustednfc.android.NfcTag#transceive}.
+</p>
+
+<TABLE BORDER="1">
+ <TR><TH> Tag Type </TH><TH> Returned string </TH></TR>
+ <TR><TD> Jewel/Topaz </TD><TD> Jewel </TD></TR>
+ <TR><TD> Mifare UltraLight </TD><TD> MifareUL </TD></TR>
+ <TR><TD> Mifare Standard 1K </TD><TD> Mifare1K </TD></TR>
+ <TR><TD> Mifare Standard 4K </TD><TD> Mifare4K </TD></TR>
+ <TR><TD> Mifare DESFIRE </TD><TD> MifareDESFIRE </TD></TR>
+ <TR><TD> Felica </TD><TD> Felica </TD></TR>
+ <TR><TD> ISO14443-4 A or B </TD><TD> Iso14443 </TD></TR>
+ <TR><TD> ISO15693 </TD><TD> Iso15693 </TD></TR>
+</TABLE>
+
+</body>
+</html>
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 8c280b4..f4d1b6e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -193,6 +193,14 @@ LOCAL_SHARED_LIBRARIES := \
libwpa_client \
libjpeg
+ifeq ($(BOARD_HAVE_NFC),true)
+LOCAL_SHARED_LIBRARIES += \
+ libnfc_jni \
+ libnfc
+
+LOCAL_CFLAGS += -DHAVE_NFC
+endif
+
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_C_INCLUDES += \
external/dbus \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index beb49c8..e5d5d8a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -170,6 +170,18 @@ extern int register_android_view_MotionEvent(JNIEnv* env);
extern int register_android_content_res_ObbScanner(JNIEnv* env);
extern int register_android_content_res_Configuration(JNIEnv* env);
+#ifdef HAVE_NFC
+extern int register_com_trustedlogic_trustednfc_android_internal_NativeNfcManager(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_internal_NativeNfcTag(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_internal_NativeNdefTag(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_NdefMessage(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_NdefRecord(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_internal_NativeP2pDevice(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_internal_NativeLlcpSocket(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_internal_NativeLlcpConnectionlessSocket(JNIEnv *env);
+extern int register_com_trustedlogic_trustednfc_android_internal_NativeLlcpServiceSocket(JNIEnv *env);
+#endif
+
static AndroidRuntime* gCurRuntime = NULL;
static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
@@ -1287,6 +1299,18 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_res_ObbScanner),
REG_JNI(register_android_content_res_Configuration),
+
+#ifdef HAVE_NFC
+ REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeNfcManager),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeNfcTag),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeNdefTag),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_NdefMessage),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_NdefRecord),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeP2pDevice),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeLlcpSocket),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeLlcpConnectionlessSocket),
+ REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeLlcpServiceSocket),
+#endif
};
/*
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index 62c89fc..2a9eacf 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -34,7 +34,17 @@ static struct {
jfieldID flags;
} gObbInfoClassInfo;
-static jboolean android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz, jstring file,
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz;
+
+ npeClazz = env->FindClass(exc);
+ LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
+
+ env->ThrowNew(npeClazz, msg);
+}
+
+static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz, jstring file,
jobject obbInfo)
{
const char* filePath = env->GetStringUTFChars(file, JNI_FALSE);
@@ -42,7 +52,8 @@ static jboolean android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject c
sp<ObbFile> obb = new ObbFile();
if (!obb->readFrom(filePath)) {
env->ReleaseStringUTFChars(file, filePath);
- return JNI_FALSE;
+ doThrow(env, "java/io/IOException", "Could not read OBB file");
+ return;
}
env->ReleaseStringUTFChars(file, filePath);
@@ -51,13 +62,13 @@ static jboolean android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject c
jstring packageName = env->NewStringUTF(packageNameStr);
if (packageName == NULL) {
- return JNI_FALSE;
+ doThrow(env, "java/io/IOException", "Could not read OBB file");
+ return;
}
env->SetObjectField(obbInfo, gObbInfoClassInfo.packageName, packageName);
env->SetIntField(obbInfo, gObbInfoClassInfo.version, obb->getVersion());
-
- return JNI_TRUE;
+ env->SetIntField(obbInfo, gObbInfoClassInfo.flags, obb->getFlags());
}
/*
@@ -65,7 +76,7 @@ static jboolean android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject c
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)Z",
+ { "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)V",
(void*) android_content_res_ObbScanner_getObbInfo },
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 68a5a14..b9eb5d6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -86,6 +86,10 @@
<protected-broadcast android:name="android.hardware.action.USB_DISCONNECTED" />
<protected-broadcast android:name="android.hardware.action.USB_STATE" />
+ <protected-broadcast android:name="com.trustedlogic.trustednfc.android.action.NDEF_TAG_DISCOVERED" />
+ <protected-broadcast android:name="com.trustedlogic.trustednfc.android.action.TRANSACTION_DETECTED" />
+ <protected-broadcast android:name="com.trustedlogic.trustednfc.android.action.LLCP_LINK_STATE_CHANGED" />
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
@@ -336,6 +340,30 @@
android:description="@string/permdesc_bluetooth"
android:label="@string/permlab_bluetooth" />
+ <!-- Allows applications to access remote NFC devices
+ @hide -->
+ <permission android:name="com.trustedlogic.trustednfc.permission.NFC_RAW"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_nfcRaw"
+ android:label="@string/permlab_nfcRaw" />
+
+ <!-- Allows applications to be notified of remote NFC devices
+ @hide -->
+ <permission android:name="com.trustedlogic.trustednfc.permission.NFC_NOTIFY"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_nfcNotify"
+ android:label="@string/permlab_nfcNotify" />
+
+ <!-- Allows applications to be notified of remote NFC LLCP devices
+ @hide -->
+ <permission android:name="com.trustedlogic.trustednfc.permission.NFC_LLCP"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_nfcLlcp"
+ android:label="@string/permlab_nfcLlcp" />
+
<!-- Allows applications to call into AccountAuthenticators. Only
the system can get this permission. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
@@ -839,6 +867,14 @@
android:description="@string/permdesc_bluetoothAdmin"
android:label="@string/permlab_bluetoothAdmin" />
+ <!-- Allows applications to change NFC connectivity settings
+ @hide -->
+ <permission android:name="com.trustedlogic.trustednfc.permission.NFC_ADMIN"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_nfcAdmin"
+ android:label="@string/permlab_nfcAdmin" />
+
<!-- Allows an application to clear the caches of all installed
applications on the device. -->
<permission android:name="android.permission.CLEAR_APP_CACHE"
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
index 9fb43b8..c21b24e 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
index e26a083..87007a3 100644
--- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_car_mode.png b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
index 60c3778..e700d79 100755..100644
--- a/core/res/res/drawable-hdpi/stat_notify_car_mode.png
+++ b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_email_generic.png b/core/res/res/drawable-hdpi/stat_notify_email_generic.png
index 87f0cd4..bc5fcab 100644
--- a/core/res/res/drawable-hdpi/stat_notify_email_generic.png
+++ b/core/res/res/drawable-hdpi/stat_notify_email_generic.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_error.png b/core/res/res/drawable-hdpi/stat_notify_error.png
index 37c8853..b3a18b3 100644..100755
--- a/core/res/res/drawable-hdpi/stat_notify_error.png
+++ b/core/res/res/drawable-hdpi/stat_notify_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_gmail.png b/core/res/res/drawable-hdpi/stat_notify_gmail.png
index 8a9140c..ea8beae 100644
--- a/core/res/res/drawable-hdpi/stat_notify_gmail.png
+++ b/core/res/res/drawable-hdpi/stat_notify_gmail.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_missed_call.png b/core/res/res/drawable-hdpi/stat_notify_missed_call.png
index d1173b4..3c19c93 100755..100644
--- a/core/res/res/drawable-hdpi/stat_notify_missed_call.png
+++ b/core/res/res/drawable-hdpi/stat_notify_missed_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_more.png b/core/res/res/drawable-hdpi/stat_notify_more.png
index 1c7f9db..f54b3d4 100755
--- a/core/res/res/drawable-hdpi/stat_notify_more.png
+++ b/core/res/res/drawable-hdpi/stat_notify_more.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png b/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
index a5e369e..fb2b26a 100644..100755
--- a/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_error.png b/core/res/res/drawable-hdpi/stat_notify_sync_error.png
index 6e3b545..26b2446 100755
--- a/core/res/res/drawable-hdpi/stat_notify_sync_error.png
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
index e9405dd..0458124 100755..100644
--- a/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
+++ b/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ebccfb6..d9177e7 100644..100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -381,8 +381,10 @@
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_storage">Storage</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permgroupdesc_storage" product="nosdcard">Access the shared storage.</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgroupdesc_storage">Access the SD card.</string>
+ <string name="permgroupdesc_storage" product="default">Access the SD card.</string>
<!-- Permissions -->
@@ -1151,6 +1153,30 @@
connections with paired devices.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_nfcAdmin">NFC administration</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_nfcAdmin">Allows an application to configure
+ the local NFC phone.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_nfcRaw">NFC full access to remote device</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_nfcRaw">Allows an application to access
+ remote NFC devices.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_nfcNotify">NFC notification from remote device</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_nfcNotify">Allows an application to be notified
+ of operations related to remote NFC devices.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_nfcLlcp">NFC notification from remote LLCP device</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_nfcLlcp">Allows an application to be notified
+ of LLCP operations related to remote NFC devices.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_disableKeyguard">disable keylock</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_disableKeyguard">Allows an application to disable
@@ -1200,10 +1226,14 @@
<string name="permdesc_writeDictionary">Allows an application to write new words into the
user dictionary.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permlab_sdcardWrite" product="nosdcard">modify/delete shared storage contents</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_sdcardWrite">modify/delete SD card contents</string>
+ <string name="permlab_sdcardWrite" product="default">modify/delete SD card contents</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permdesc_sdcardWrite" product="nosdcard">Allows an application to write to the shared storage.</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_sdcardWrite">Allows an application to write to the SD card.</string>
+ <string name="permdesc_sdcardWrite" product="default">Allows an application to write to the SD card.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_cache_filesystem">access the cache filesystem</string>
@@ -1213,31 +1243,28 @@
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
- <string name="policylab_limitPassword">Limit password</string>
+ <string name="policylab_limitPassword">Set password rules</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_limitPassword">Restrict the types of passwords you
- are allowed to use.</string>
+ <string name="policydesc_limitPassword">Control the length and the characters allowed in
+ screen-unlock passwords</string>
<!-- Title of policy access to watch user login attempts -->
- <string name="policylab_watchLogin">Watch login attempts</string>
+ <string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
<!-- Description of policy access to watch user login attempts -->
- <string name="policydesc_watchLogin">Monitor failed attempts to login to
- the device, to perform some action.</string>
+ <string name="policydesc_watchLogin">Monitor the number of incorrect passwords entered when unlocking
+ the screen, and lock the phone or erase all the phone\'s data if too many incorrect passwords are entered
+ </string>
<!-- Title of policy access to reset user's password -->
- <string name="policylab_resetPassword">Reset password</string>
+ <string name="policylab_resetPassword">Change the screen-unlock password</string>
<!-- Description of policy access to reset user's password -->
- <string name="policydesc_resetPassword">Force your password
- to a new value, requiring the administrator give it to you
- before you can log in.</string>
+ <string name="policydesc_resetPassword">Change the screen-unlock password</string>
<!-- Title of policy access to force lock the device -->
- <string name="policylab_forceLock">Force lock</string>
+ <string name="policylab_forceLock">Lock the screen</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_forceLock">Control when device locks,
- requiring you re-enter its password.</string>
+ <string name="policydesc_forceLock">Control how and when the screen locks</string>
<!-- Title of policy access to wipe the user's data -->
<string name="policylab_wipeData">Erase all data</string>
<!-- Description of policy access to wipe the user's data -->
- <string name="policydesc_wipeData">Perform a factory reset, deleting
- all of your data without any confirmation.</string>
+ <string name="policydesc_wipeData">Erase the phone\'s data without warning, by performing a factory data reset</string>
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -2058,12 +2085,16 @@
<!-- See USB_STORAGE. USB_STORAGE_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to mount. This is the title. -->
<string name="usb_storage_title">USB connected</string>
+ <!-- See USB_STORAGE. This is the message. [CHAR LIMIT=NONE] -->
+ <string name="usb_storage_message" product="nosdcard">You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android\u2018s shared storage.</string>
<!-- See USB_STORAGE. This is the message. -->
- <string name="usb_storage_message">You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>
+ <string name="usb_storage_message" product="default">You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>
<!-- See USB_STORAGE. This is the button text to mount the phone on the computer. -->
<string name="usb_storage_button_mount">Turn on USB storage</string>
+ <!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. [CHAR LIMIT=NONE] -->
+ <string name="usb_storage_error_message" product="nosdcard">There is a problem using your shared storage for USB storage.</string>
<!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. -->
- <string name="usb_storage_error_message">There is a problem using your SD card for USB storage.</string>
+ <string name="usb_storage_error_message" product="default">There is a problem using your SD card for USB storage.</string>
<!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across. This is the title -->
<string name="usb_storage_notification_title">USB connected</string>
<!-- See USB_STORAGE. This is the message. -->
@@ -2078,8 +2109,10 @@
<!-- This is the label for the activity, and should never be visible to the user. -->
<!-- See USB_STORAGE_STOP. USB_STORAGE_STOP_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to stop usb storage. This is the title. -->
<string name="usb_storage_stop_title">USB storage in use</string>
+ <!-- See USB_STORAGE_STOP. This is the message. [CHAR LIMIT=NONE] -->
+ <string name="usb_storage_stop_message" product="nosdcard">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s shared storage from your computer.</string>
<!-- See USB_STORAGE_STOP. This is the message. -->
- <string name="usb_storage_stop_message">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s SD card from your computer.</string>
+ <string name="usb_storage_stop_message" product="default">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s SD card from your computer.</string>
<!-- See USB_STORAGE_STOP. This is the button text to stop usb storage. -->
<string name="usb_storage_stop_button_mount">Turn off USB storage</string>
<!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
@@ -2096,10 +2129,14 @@
<!-- External media format dialog strings -->
<!-- This is the label for the activity, and should never be visible to the user. -->
+ <!-- See EXTMEDIA_FORMAT. EXTMEDIA_FORMAT_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to format the SD card. This is the title. [CHAR LIMIT=20] -->
+ <string name="extmedia_format_title" product="nosdcard">Format shared storage</string>
<!-- See EXTMEDIA_FORMAT. EXTMEDIA_FORMAT_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to format the SD card. This is the title. -->
- <string name="extmedia_format_title">Format SD card</string>
+ <string name="extmedia_format_title" product="default">Format SD card</string>
+ <!-- See EXTMEDIA_FORMAT. This is the message. [CHAR LIMIT=NONE] -->
+ <string name="extmedia_format_message" product="nosdcard">Format shared storage, erasing all files stored there? Action cannot be reversed!</string>
<!-- See EXTMEDIA_FORMAT. This is the message. -->
- <string name="extmedia_format_message">Are you sure you want to format the SD card? All data on your card will be lost.</string>
+ <string name="extmedia_format_message" product="default">Are you sure you want to format the SD card? All data on your card will be lost.</string>
<!-- See EXTMEDIA_FORMAT. This is the button text to format the sd card. -->
<string name="extmedia_format_button_format">Format</string>
@@ -2124,29 +2161,51 @@
<string name="candidates_style"><u>candidates</u></string>
<!-- External media notification strings -->
+ <!-- Shown when external media is being checked [CHAR LIMIT=30] -->
+ <string name="ext_media_checking_notification_title" product="nosdcard">Preparing shared storage</string>
<!-- Shown when external media is being checked -->
- <string name="ext_media_checking_notification_title">Preparing SD card</string>
+ <string name="ext_media_checking_notification_title" product="default">Preparing SD card</string>
<string name="ext_media_checking_notification_message">Checking for errors.</string>
+ <!-- Shown when external media is blank (or unsupported filesystem) [CHAR LIMIT=30] -->
+ <string name="ext_media_nofs_notification_title" product="nosdcard">Blank shared storage</string>
<!-- Shown when external media is blank (or unsupported filesystem) -->
- <string name="ext_media_nofs_notification_title">Blank SD card</string>
- <string name="ext_media_nofs_notification_message">SD card blank or has unsupported filesystem.</string>
+ <string name="ext_media_nofs_notification_title" product="default">Blank SD card</string>
+ <!-- Shown when shared storage cannot be read. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_nofs_notification_message" product="nosdcard">Shared storage blank or has unsupported filesystem.</string>
+ <string name="ext_media_nofs_notification_message" product="default">SD card blank or has unsupported filesystem.</string>
+ <!-- Shown when external media is unmountable (corrupt)) [CHAR LIMIT=30] -->
+ <string name="ext_media_unmountable_notification_title" product="nosdcard">Damaged shared storage</string>
<!-- Shown when external media is unmountable (corrupt)) -->
- <string name="ext_media_unmountable_notification_title">Damaged SD card</string>
- <string name="ext_media_unmountable_notification_message">SD card damaged. You may have to reformat it.</string>
+ <string name="ext_media_unmountable_notification_title" product="default">Damaged SD card</string>
+ <!-- Shown when shared storage cannot be read. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_unmountable_notification_message" product="nosdcard">Shared storage damaged. You may have to reformat it.</string>
+ <string name="ext_media_unmountable_notification_message" product="default">SD card damaged. You may have to reformat it.</string>
+ <!-- Shown when external media is unsafely removed [CHAR LIMIT=30] -->
+ <string name="ext_media_badremoval_notification_title" product="nosdcard">Shared storage unexpectedly removed</string>
<!-- Shown when external media is unsafely removed -->
- <string name="ext_media_badremoval_notification_title">SD card unexpectedly removed</string>
- <string name="ext_media_badremoval_notification_message">Unmount SD card before removing to avoid data loss.</string>
+ <string name="ext_media_badremoval_notification_title" product="default">SD card unexpectedly removed</string>
+ <!-- Shown when external media is unsafely removed. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_badremoval_notification_message" product="nosdcard">Unmount shared storage before removing to avoid data loss.</string>
+ <string name="ext_media_badremoval_notification_message" product="default">Unmount SD card before removing to avoid data loss.</string>
+ <!-- Shown when external media has been safely removed [CHAR LIMIT=30] -->
+ <string name="ext_media_safe_unmount_notification_title" product="nosdcard">Shared storage safe to remove</string>
<!-- Shown when external media has been safely removed -->
- <string name="ext_media_safe_unmount_notification_title">SD card safe to remove</string>
- <string name="ext_media_safe_unmount_notification_message">You can safely remove SD card.</string>
+ <string name="ext_media_safe_unmount_notification_title" product="default">SD card safe to remove</string>
+ <!-- Shown when external media has been safely removed. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_safe_unmount_notification_message" product="nosdcard">You can safely remove shared storage.</string>
+ <string name="ext_media_safe_unmount_notification_message" product="default">You can safely remove SD card.</string>
+ <!-- Shown when external media is missing [CHAR LIMIT=30] -->
+ <string name="ext_media_nomedia_notification_title" product="nosdcard">Removed shared storage</string>
<!-- Shown when external media is missing -->
- <string name="ext_media_nomedia_notification_title">Removed SD card</string>
- <string name="ext_media_nomedia_notification_message">SD card removed. Insert a new one.</string>
+ <string name="ext_media_nomedia_notification_title" product="default">Removed SD card</string>
+ <!-- Shown when external media is missing. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_nomedia_notification_message" product="nosdcard">Shared storage removed. Insert new media.</string>
+ <string name="ext_media_nomedia_notification_message" product="default">SD card removed. Insert a new one.</string>
<!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
<string name="activity_list_empty">No matching activities found</string>
diff --git a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index a7ec7d5..ed42e64 100644
--- a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package android.net;
+package android.app;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.ConnectivityManager;
-import android.net.DownloadManager;
import android.net.NetworkInfo;
-import android.net.DownloadManager.Query;
-import android.net.DownloadManager.Request;
+import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
diff --git a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java
index a61f02d..38f336e 100644
--- a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package android.net;
+package android.app;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
+import android.app.DownloadManagerBaseTest.DataType;
+import android.app.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
-import android.net.DownloadManager;
-import android.net.DownloadManager.Query;
-import android.net.DownloadManager.Request;
-import android.net.DownloadManagerBaseTest.DataType;
-import android.net.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver;
+import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
diff --git a/core/tests/coretests/src/android/net/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index 9fa8620..4ff0295 100644
--- a/core/tests/coretests/src/android/net/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-package android.net;
+package android.app;
import java.io.File;
import java.util.Random;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
import android.database.Cursor;
-import android.net.DownloadManager.Query;
-import android.net.DownloadManager.Request;
+import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
index 576765c..7206f4a 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
@@ -19,7 +19,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- ../../../coretests/src/android/net/DownloadManagerBaseTest.java
+ ../../../coretests/src/android/app/DownloadManagerBaseTest.java
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
LOCAL_SDK_VERSION := current
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
index f21e7ac..c0f670b 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
@@ -15,13 +15,13 @@
*/
package com.android.frameworks.downloadmanagertests;
+import android.app.DownloadManager;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
+import android.app.DownloadManagerBaseTest;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
-import android.net.DownloadManager;
-import android.net.DownloadManager.Query;
-import android.net.DownloadManager.Request;
-import android.net.DownloadManagerBaseTest;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 9a09586..ed2f7d7 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -27,6 +27,7 @@ namespace android {
class MediaSource;
class AudioTrack;
+class AwesomePlayer;
class AudioPlayer : public TimeSource {
public:
@@ -35,7 +36,9 @@ public:
SEEK_COMPLETE
};
- AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink);
+ AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
+ AwesomePlayer *audioObserver = NULL);
+
virtual ~AudioPlayer();
// Caller retains ownership of "source".
@@ -91,6 +94,7 @@ private:
MediaBuffer *mFirstBuffer;
sp<MediaPlayerBase::AudioSink> mAudioSink;
+ AwesomePlayer *mObserver;
static void AudioCallback(int event, void *user, void *info);
void AudioCallback(int event, void *info);
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
new file mode 100644
index 0000000..551ca01
--- /dev/null
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef MPEG2TS_WRITER_H_
+
+#define MPEG2TS_WRITER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaWriter.h>
+
+namespace android {
+
+struct MPEG2TSWriter : public MediaWriter {
+ MPEG2TSWriter(const char *filename);
+
+ virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t start(MetaData *param = NULL);
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual bool reachedEOS();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+ virtual ~MPEG2TSWriter();
+
+private:
+ enum {
+ kWhatSourceNotify = 'noti'
+ };
+
+ struct SourceInfo;
+
+ FILE *mFile;
+ sp<ALooper> mLooper;
+ sp<AHandlerReflector<MPEG2TSWriter> > mReflector;
+
+ bool mStarted;
+
+ Vector<sp<SourceInfo> > mSources;
+ size_t mNumSourcesDone;
+
+ int64_t mNumTSPacketsWritten;
+ int64_t mNumTSPacketsBeforeMeta;
+
+ void writeTS();
+ void writeProgramAssociationTable();
+ void writeProgramMap();
+ void writeAccessUnit(int32_t sourceIndex, const sp<ABuffer> &buffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSWriter);
+};
+
+} // namespace android
+
+#endif // MPEG2TS_WRITER_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 1594e31..ab2f11d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -95,6 +95,8 @@ enum {
// Ogg files can be tagged to be automatically looping...
kKeyAutoLoop = 'autL', // bool (int32_t)
+
+ kKeyValidSamples = 'valD', // int32_t
};
enum {
diff --git a/include/storage/IMountService.h b/include/storage/IMountService.h
index a2735a4..436fc38 100644
--- a/include/storage/IMountService.h
+++ b/include/storage/IMountService.h
@@ -62,7 +62,8 @@ public:
virtual void finishMediaUpdate() = 0;
virtual void mountObb(const String16& filename, const String16& key,
const sp<IObbActionListener>& token) = 0;
- virtual void unmountObb(const String16& filename, const bool force) = 0;
+ virtual void unmountObb(const String16& filename, const bool force,
+ const sp<IObbActionListener>& token) = 0;
virtual bool isObbMounted(const String16& filename) = 0;
virtual bool getMountedObbPath(const String16& filename, String16& path) = 0;
};
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index 902bb27..3ad9319 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -429,8 +429,8 @@ public:
reply.readExceptionCode();
}
- void mountObb(const String16& filename, const String16& key, const sp<
- IObbActionListener>& token)
+ void mountObb(const String16& filename, const String16& key,
+ const sp<IObbActionListener>& token)
{
Parcel data, reply;
data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
@@ -448,7 +448,7 @@ public:
}
}
- void unmountObb(const String16& filename, const bool force)
+ void unmountObb(const String16& filename, const bool force, const sp<IObbActionListener>& token)
{
Parcel data, reply;
data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 5da1676..9544a95 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -1070,7 +1070,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
}
// Figure out whether splitting will be allowed for this window.
- if (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH) {
+ if (newTouchedWindow
+ && (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH)) {
// New window supports splitting.
isSplit = true;
} else if (isSplit) {
@@ -1916,6 +1917,14 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
// The first/last pointer went down/up.
action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN
? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
+ } else {
+ // A secondary pointer went down/up.
+ uint32_t splitPointerIndex = 0;
+ while (pointerId != splitPointerIds[splitPointerIndex]) {
+ splitPointerIndex += 1;
+ }
+ action = maskedAction | (splitPointerIndex
+ << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
}
} else {
// An unrelated pointer changed.
diff --git a/location/Android.mk b/location/Android.mk
new file mode 100644
index 0000000..12db2f7
--- /dev/null
+++ b/location/Android.mk
@@ -0,0 +1,19 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(TARGET_BUILD_APPS),)
+include $(call all-makefiles-under, $(LOCAL_PATH))
+endif
diff --git a/location/lib/Android.mk b/location/lib/Android.mk
new file mode 100644
index 0000000..a06478a
--- /dev/null
+++ b/location/lib/Android.mk
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+# the library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= com.android.location.provider
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ $(call all-subdir-java-files)
+
+include $(BUILD_JAVA_LIBRARY)
+
+
+# ==== com.google.location.xml lib def ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := com.android.location.provider.xml
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/location/lib/com.android.location.provider.xml b/location/lib/com.android.location.provider.xml
new file mode 100644
index 0000000..000e68f
--- /dev/null
+++ b/location/lib/com.android.location.provider.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<permissions>
+ <library name="com.android.location.provider"
+ file="/system/framework/com.android.location.provider.jar" />
+</permissions>
diff --git a/location/java/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java
index 493c631..666bb02 100644
--- a/location/java/android/location/provider/GeocodeProvider.java
+++ b/location/lib/java/com/android/location/provider/GeocodeProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.location.provider;
+package com.android.location.provider;
import android.os.IBinder;
@@ -80,4 +80,3 @@ public abstract class GeocodeProvider {
return mProvider;
}
}
-
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/lib/java/com/android/location/provider/LocationProvider.java
index 14dea14..3714f40 100644
--- a/location/java/android/location/provider/LocationProvider.java
+++ b/location/lib/java/com/android/location/provider/LocationProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.location.provider;
+package com.android.location.provider;
import android.content.Context;
import android.net.NetworkInfo;
@@ -356,4 +356,3 @@ public abstract class LocationProvider {
*/
public abstract void onRemoveListener(int uid, WorkSource ws);
}
-
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 8f40130..ebe3302 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -63,7 +63,6 @@ namespace {
// Flag to allow a one time init of global memory, only happens on first call ever
int LvmInitFlag = LVM_FALSE;
-int LvmSessionsActive = 0;
SessionContext GlobalSessionMemory[LVM_MAX_SESSIONS];
int SessionIndex[LVM_MAX_SESSIONS];
@@ -189,16 +188,19 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
effect_interface_t *pInterface){
- int ret;
+ int ret = 0;
int sessionNo;
int i;
- EffectContext *pContext = new EffectContext;
+ EffectContext *pContext = NULL;
+ bool newBundle = false;
+ SessionContext *pSessionContext;
LOGV("\n\tEffectCreate start session %d", sessionId);
if (pInterface == NULL || uuid == NULL){
LOGV("\tLVM_ERROR : EffectCreate() called with NULL pointer");
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
if(LvmInitFlag == LVM_FALSE){
@@ -207,8 +209,6 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
LvmGlobalBundle_init();
}
- LOGV("\tEffectCreate: There are %d LVM sessions acive\n", LvmSessionsActive);
-
// Find next available sessionNo
for(i=0; i<LVM_MAX_SESSIONS; i++){
if((SessionIndex[i] == LVM_UNUSED_SESSION)||(SessionIndex[i] == sessionId)){
@@ -221,23 +221,20 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
if(i==LVM_MAX_SESSIONS){
LOGV("\tLVM_ERROR : Cannot find memory to allocate for current session");
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
+
+ pContext = new EffectContext;
+
// If this is the first create in this session
if(GlobalSessionMemory[sessionNo].bBundledEffectsEnabled == LVM_FALSE){
LOGV("\tEffectCreate - This is the first effect in current sessionId %d sessionNo %d",
sessionId, sessionNo);
- LvmSessionsActive++;
-
- if(LvmSessionsActive >= LVM_MAX_SESSIONS){
- LOGV("\tLVM_ERROR : Number of active session is greater than LVM_MAX_SESSIONS (%d)",
- LVM_MAX_SESSIONS);
- return -EINVAL;
- }
-
GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_TRUE;
GlobalSessionMemory[sessionNo].pBundledContext = new BundledEffectContext;
+ newBundle = true;
pContext->pBundledContext = GlobalSessionMemory[sessionNo].pBundledContext;
pContext->pBundledContext->SessionNo = sessionNo;
@@ -251,17 +248,16 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE;
pContext->pBundledContext->NumberEffectsEnabled = 0;
pContext->pBundledContext->NumberEffectsCalled = 0;
- pContext->pBundledContext->frameCount = 0;
pContext->pBundledContext->firstVolume = LVM_TRUE;
#ifdef LVM_PCM
-
char fileName[256];
snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_in.pcm", pContext->pBundledContext);
pContext->pBundledContext->PcmInPtr = fopen(fileName, "w");
if (pContext->pBundledContext->PcmInPtr == NULL) {
LOGV("cannot open %s", fileName);
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_out.pcm", pContext->pBundledContext);
@@ -270,7 +266,8 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
LOGV("cannot open %s", fileName);
fclose(pContext->pBundledContext->PcmInPtr);
pContext->pBundledContext->PcmInPtr = NULL;
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
#endif
@@ -285,15 +282,18 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
pContext->pBundledContext->bMuteEnabled = LVM_FALSE;
pContext->pBundledContext->bStereoPositionEnabled = LVM_FALSE;
pContext->pBundledContext->positionSaved = 0;
+ pContext->pBundledContext->workBuffer = NULL;
+ pContext->pBundledContext->frameCount = -1;
+ pContext->pBundledContext->SamplesToExitCountVirt = 0;
+ pContext->pBundledContext->SamplesToExitCountBb = 0;
+ pContext->pBundledContext->SamplesToExitCountEq = 0;
LOGV("\tEffectCreate - Calling LvmBundle_init");
ret = LvmBundle_init(pContext);
if (ret < 0){
LOGV("\tLVM_ERROR : EffectCreate() Bundle init failed");
- delete pContext->pBundledContext;
- delete pContext;
- return ret;
+ goto exit;
}
}
else{
@@ -304,13 +304,14 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
}
LOGV("\tEffectCreate - pBundledContext is %p", pContext->pBundledContext);
- SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
+ pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
// Create each Effect
if (memcmp(uuid, &gBassBoostDescriptor.uuid, sizeof(effect_uuid_t)) == 0){
// Create Bass Boost
LOGV("\tEffectCreate - Effect to be created is LVM_BASS_BOOST");
pSessionContext->bBassInstantiated = LVM_TRUE;
+ pContext->pBundledContext->SamplesToExitCountBb = 0;
pContext->itfe = &gLvmEffectInterface;
pContext->EffectType = LVM_BASS_BOOST;
@@ -318,6 +319,7 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
// Create Virtualizer
LOGV("\tEffectCreate - Effect to be created is LVM_VIRTUALIZER");
pSessionContext->bVirtualizerInstantiated=LVM_TRUE;
+ pContext->pBundledContext->SamplesToExitCountVirt = 0;
pContext->itfe = &gLvmEffectInterface;
pContext->EffectType = LVM_VIRTUALIZER;
@@ -325,6 +327,7 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
// Create Equalizer
LOGV("\tEffectCreate - Effect to be created is LVM_EQUALIZER");
pSessionContext->bEqualizerInstantiated = LVM_TRUE;
+ pContext->pBundledContext->SamplesToExitCountEq = 0;
pContext->itfe = &gLvmEffectInterface;
pContext->EffectType = LVM_EQUALIZER;
@@ -338,46 +341,77 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
}
else{
LOGV("\tLVM_ERROR : EffectCreate() invalid UUID");
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
- *pInterface = (effect_interface_t)pContext;
+exit:
+ if (ret != 0) {
+ if (pContext != NULL) {
+ if (newBundle) {
+ GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_FALSE;
+ SessionIndex[sessionNo] = LVM_UNUSED_SESSION;
+ delete pContext->pBundledContext;
+ }
+ delete pContext;
+ }
+ *pInterface = (effect_interface_t)NULL;
+ } else {
+ *pInterface = (effect_interface_t)pContext;
+ }
LOGV("\tEffectCreate end..\n\n");
- return 0;
+ return ret;
} /* end EffectCreate */
extern "C" int EffectRelease(effect_interface_t interface){
LOGV("\n\tEffectRelease start %p", interface);
EffectContext * pContext = (EffectContext *)interface;
- LOGV("\n\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext);
+ LOGV("\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext);
if (pContext == NULL){
LOGV("\tLVM_ERROR : EffectRelease called with NULL pointer");
return -EINVAL;
}
-
- Effect_setEnabled(pContext, LVM_FALSE);
-
SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
// Clear the instantiated flag for the effect
+ // protect agains the case where an effect is un-instantiated without being disabled
if(pContext->EffectType == LVM_BASS_BOOST) {
LOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag");
pSessionContext->bBassInstantiated = LVM_FALSE;
+ if(pContext->pBundledContext->SamplesToExitCountBb > 0){
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ }
+ pContext->pBundledContext->SamplesToExitCountBb = 0;
} else if(pContext->EffectType == LVM_VIRTUALIZER) {
LOGV("\tEffectRelease LVM_VIRTUALIZER Clearing global intstantiated flag");
pSessionContext->bVirtualizerInstantiated = LVM_FALSE;
+ if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ }
+ pContext->pBundledContext->SamplesToExitCountVirt = 0;
} else if(pContext->EffectType == LVM_EQUALIZER) {
LOGV("\tEffectRelease LVM_EQUALIZER Clearing global intstantiated flag");
pSessionContext->bEqualizerInstantiated =LVM_FALSE;
+ if(pContext->pBundledContext->SamplesToExitCountEq > 0){
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ }
+ pContext->pBundledContext->SamplesToExitCountEq = 0;
} else if(pContext->EffectType == LVM_VOLUME) {
LOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag");
pSessionContext->bVolumeInstantiated = LVM_FALSE;
+ if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ }
} else {
LOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n");
}
+ // Disable effect, in this case ignore errors (return codes)
+ // if an effect has already been disabled
+ Effect_setEnabled(pContext, LVM_FALSE);
+
// if all effects are no longer instantiaed free the lvm memory and delete BundledEffectContext
if ((pSessionContext->bBassInstantiated == LVM_FALSE) &&
(pSessionContext->bVolumeInstantiated == LVM_FALSE) &&
@@ -395,8 +429,6 @@ extern "C" int EffectRelease(effect_interface_t interface){
}
#endif
- LvmSessionsActive--;
- LOGV("\tEffectRelease: There are %d LVM sessions remaining\n", LvmSessionsActive);
// Clear the SessionIndex
for(int i=0; i<LVM_MAX_SESSIONS; i++){
@@ -409,11 +441,14 @@ extern "C" int EffectRelease(effect_interface_t interface){
}
LOGV("\tEffectRelease: All effects are no longer instantiated\n");
- pSessionContext->bBundledEffectsEnabled =LVM_FALSE;
+ pSessionContext->bBundledEffectsEnabled = LVM_FALSE;
pSessionContext->pBundledContext = LVM_NULL;
LOGV("\tEffectRelease: Freeing LVM Bundle memory\n");
LvmEffect_free(pContext);
LOGV("\tEffectRelease: Deleting LVM Bundle context %p\n", pContext->pBundledContext);
+ if (pContext->pBundledContext->workBuffer != NULL) {
+ free(pContext->pBundledContext->workBuffer);
+ }
delete pContext->pBundledContext;
pContext->pBundledContext = LVM_NULL;
}
@@ -643,6 +678,14 @@ int LvmBundle_init(EffectContext *pContext){
return 0;
} /* end LvmBundle_init */
+
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
//----------------------------------------------------------------------------
// LvmBundle_process()
//----------------------------------------------------------------------------
@@ -668,39 +711,25 @@ int LvmBundle_process(LVM_INT16 *pIn,
LVM_ControlParams_t ActiveParams; /* Current control Parameters */
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
-
LVM_INT16 *pOutTmp;
+
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
pOutTmp = pOut;
}else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
- pOutTmp = (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
- if(pOutTmp == NULL){
- LOGV("\tLVM_ERROR : LvmBundle_process failed to allocate memory for "
- "EFFECT_BUFFER_ACCESS_ACCUMULATE mode");
- return -EINVAL;
+ if (pContext->pBundledContext->frameCount != frameCount) {
+ if (pContext->pBundledContext->workBuffer != NULL) {
+ free(pContext->pBundledContext->workBuffer);
+ }
+ pContext->pBundledContext->workBuffer =
+ (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+ pContext->pBundledContext->frameCount = frameCount;
}
+ pOutTmp = pContext->pBundledContext->workBuffer;
}else{
LOGV("LVM_ERROR : LvmBundle_process invalid access mode");
return -EINVAL;
}
- /* Get the current settings */
- LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance,
- &ActiveParams);
-
- LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "LvmBundle_process")
- if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-
- pContext->pBundledContext->frameCount++;
- if(pContext->pBundledContext->frameCount == 100)
- {
- //LOGV("\tBB: %d VIRT: %d EQ: %d, session (%d), context is %p\n",
- //ActiveParams.BE_OperatingMode,
- //ActiveParams.VirtualizerOperatingMode, ActiveParams.EQNB_OperatingMode,
- //pContext->pBundledContext->SessionNo, pContext->pBundledContext);
- pContext->pBundledContext->frameCount = 0;
- }
-
#ifdef LVM_PCM
fwrite(pIn, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmInPtr);
fflush(pContext->pBundledContext->PcmInPtr);
@@ -725,9 +754,8 @@ int LvmBundle_process(LVM_INT16 *pIn,
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
for (int i=0; i<frameCount*2; i++){
- pOut[i] += pOutTmp[i];
+ pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
}
- free(pOutTmp);
}
return 0;
} /* end LvmBundle_process */
@@ -813,15 +841,15 @@ int LvmEffect_disable(EffectContext *pContext){
ActiveParams.BE_OperatingMode = LVM_BE_OFF;
}
if(pContext->EffectType == LVM_VIRTUALIZER) {
- LOGV("\tLvmEffect_disable : Enabling LVM_VIRTUALIZER");
+ LOGV("\tLvmEffect_disable : Disabling LVM_VIRTUALIZER");
ActiveParams.VirtualizerOperatingMode = LVM_MODE_OFF;
}
if(pContext->EffectType == LVM_EQUALIZER) {
- LOGV("\tLvmEffect_disable : Enabling LVM_EQUALIZER");
+ LOGV("\tLvmEffect_disable : Disabling LVM_EQUALIZER");
ActiveParams.EQNB_OperatingMode = LVM_EQNB_OFF;
}
if(pContext->EffectType == LVM_VOLUME) {
- LOGV("\tLvmEffect_disable : Enabling LVM_VOLUME");
+ LOGV("\tLvmEffect_disable : Disabling LVM_VOLUME");
}
LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
@@ -2406,85 +2434,114 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
switch (pContext->EffectType) {
case LVM_BASS_BOOST:
if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already enabled");
+ LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already enabled");
return -EINVAL;
}
+ if(pContext->pBundledContext->SamplesToExitCountBb <= 0){
+ pContext->pBundledContext->NumberEffectsEnabled++;
+ }
pContext->pBundledContext->SamplesToExitCountBb =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
pContext->pBundledContext->bBassEnabled = LVM_TRUE;
break;
case LVM_EQUALIZER:
if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already enabled");
+ LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already enabled");
return -EINVAL;
}
+ if(pContext->pBundledContext->SamplesToExitCountEq <= 0){
+ pContext->pBundledContext->NumberEffectsEnabled++;
+ }
pContext->pBundledContext->SamplesToExitCountEq =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE;
break;
case LVM_VIRTUALIZER:
if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already enabled");
+ LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already enabled");
return -EINVAL;
}
+ if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){
+ pContext->pBundledContext->NumberEffectsEnabled++;
+ }
pContext->pBundledContext->SamplesToExitCountVirt =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE;
break;
case LVM_VOLUME:
if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already enabled");
+ LOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled");
return -EINVAL;
}
+ pContext->pBundledContext->NumberEffectsEnabled++;
pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
break;
default:
- LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+ LOGV("\tEffect_setEnabled() invalid effect type");
return -EINVAL;
}
- pContext->pBundledContext->NumberEffectsEnabled++;
LvmEffect_enable(pContext);
} else {
switch (pContext->EffectType) {
case LVM_BASS_BOOST:
if (pContext->pBundledContext->bBassEnabled == LVM_FALSE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already disabled");
+ LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already disabled");
return -EINVAL;
}
pContext->pBundledContext->bBassEnabled = LVM_FALSE;
break;
case LVM_EQUALIZER:
if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already disabled");
+ LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already disabled");
return -EINVAL;
}
pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
break;
case LVM_VIRTUALIZER:
if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already disabled");
+ LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already disabled");
return -EINVAL;
}
pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
break;
case LVM_VOLUME:
if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) {
- LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already disabled");
+ LOGV("\tEffect_setEnabled() LVM_VOLUME is already disabled");
return -EINVAL;
}
pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
break;
default:
- LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+ LOGV("\tEffect_setEnabled() invalid effect type");
return -EINVAL;
}
- pContext->pBundledContext->NumberEffectsEnabled--;
LvmEffect_disable(pContext);
}
return 0;
}
+//----------------------------------------------------------------------------
+// LVC_Convert_VolToDb()
+//----------------------------------------------------------------------------
+// Purpose:
+// Convery volume in Q24 to dB
+//
+// Inputs:
+// vol: Q.24 volume dB
+//
+//-----------------------------------------------------------------------
+
+int16_t LVC_Convert_VolToDb(uint32_t vol){
+ int16_t dB;
+
+ dB = LVC_ToDB_s32Tos16(vol <<7);
+ dB = (dB +8)>>4;
+ dB = (dB <-96) ? -96 : dB ;
+
+ return dB;
+}
+
} // namespace
} // namespace
@@ -2493,32 +2550,31 @@ extern "C" int Effect_process(effect_interface_t self,
audio_buffer_t *inBuffer,
audio_buffer_t *outBuffer){
EffectContext * pContext = (EffectContext *) self;
- LVM_ControlParams_t ActiveParams; /* Current control Parameters */
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
int status = 0;
- int status2Sec = 0;
int lvmStatus = 0;
LVM_INT16 *in = (LVM_INT16 *)inBuffer->raw;
LVM_INT16 *out = (LVM_INT16 *)outBuffer->raw;
-//LOGV("\tEffect_process Start : Enabled = %d Called = %d",
-//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled);
-// LOGV("\tEffect_process Start : Samples left %d %d %d",
+//LOGV("\tEffect_process Start : Enabled = %d Called = %d (%8d %8d %8d)",
+//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled,
// pContext->pBundledContext->SamplesToExitCountBb,
// pContext->pBundledContext->SamplesToExitCountVirt,
// pContext->pBundledContext->SamplesToExitCountEq);
-// LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
-// LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeGetStereoPosition")
-// if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-// LOGV("\tEffect_process Internal Operating Modes: BB %d VIRT %d EQ %d",
-// ActiveParams.BE_OperatingMode, ActiveParams.VirtualizerOperatingMode,
-// ActiveParams.EQNB_OperatingMode);
-
if (pContext == NULL){
LOGV("\tLVM_ERROR : Effect_process() ERROR pContext == NULL");
return -EINVAL;
}
+
+ //if(pContext->EffectType == LVM_BASS_BOOST){
+ // LOGV("\tEffect_process: Effect type is BASS_BOOST");
+ //}else if(pContext->EffectType == LVM_EQUALIZER){
+ // LOGV("\tEffect_process: Effect type is LVM_EQUALIZER");
+ //}else if(pContext->EffectType == LVM_VIRTUALIZER){
+ // LOGV("\tEffect_process: Effect type is LVM_VIRTUALIZER");
+ //}
+
if (inBuffer == NULL || inBuffer->raw == NULL ||
outBuffer == NULL || outBuffer->raw == NULL ||
inBuffer->frameCount != outBuffer->frameCount){
@@ -2529,70 +2585,57 @@ extern "C" int Effect_process(effect_interface_t self,
(pContext->EffectType == LVM_BASS_BOOST)){
//LOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled");
if(pContext->pBundledContext->SamplesToExitCountBb > 0){
- status2Sec = -ENODATA;
pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * 2; // STEREO
//LOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
// pContext->pBundledContext->SamplesToExitCountBb);
} else {
status = -ENODATA;
+ pContext->pBundledContext->NumberEffectsEnabled--;
}
}
if ((pContext->pBundledContext->bVolumeEnabled == LVM_FALSE)&&
(pContext->EffectType == LVM_VOLUME)){
//LOGV("\tEffect_process() LVM_VOLUME Effect is not enabled");
status = -ENODATA;
+ pContext->pBundledContext->NumberEffectsEnabled--;
}
if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&&
(pContext->EffectType == LVM_EQUALIZER)){
//LOGV("\tEffect_process() LVM_EQUALIZER Effect is not enabled");
if(pContext->pBundledContext->SamplesToExitCountEq > 0){
- status2Sec = -ENODATA;
pContext->pBundledContext->SamplesToExitCountEq -= outBuffer->frameCount * 2; // STEREO
- //LOGV("\tEffect_process: Waiting for 2 secs to turn off EQUALIZER, %d samples left",
+ //LOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left",
// pContext->pBundledContext->SamplesToExitCountEq);
} else {
status = -ENODATA;
+ pContext->pBundledContext->NumberEffectsEnabled--;
}
}
if ((pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE)&&
(pContext->EffectType == LVM_VIRTUALIZER)){
//LOGV("\tEffect_process() LVM_VIRTUALIZER Effect is not enabled");
if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
- status2Sec = -ENODATA;
pContext->pBundledContext->SamplesToExitCountVirt -= outBuffer->frameCount * 2;// STEREO
- //LOGV("\tEffect_process: Waiting for 2 secs to turn off VIRTUALIZER, %d samples left",
+ //LOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left",
// pContext->pBundledContext->SamplesToExitCountVirt);
} else {
status = -ENODATA;
+ pContext->pBundledContext->NumberEffectsEnabled--;
}
}
- // If this is the last frame of an effect process its output with no effect
- if(status == -ENODATA){
- if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
- //LOGV("\tLVM_ERROR : Effect_process() accumulating last frame into output buffer");
- //LOGV("\tLVM_ERROR : Effect_process() trying copying last frame into output buffer");
- //LOGV("\tLVM_ERROR : Enabled = %d Called = %d",
- //pContext->pBundledContext->NumberEffectsEnabled,
- //pContext->pBundledContext->NumberEffectsCalled);
-
- }else{
- //LOGV("\tLVM_ERROR : Effect_process() copying last frame into output buffer");
- }
- }
-
- if((status2Sec != -ENODATA)&&(status != -ENODATA)){
+ if(status != -ENODATA){
pContext->pBundledContext->NumberEffectsCalled++;
}
if(pContext->pBundledContext->NumberEffectsCalled ==
pContext->pBundledContext->NumberEffectsEnabled){
- //LOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d",
+ //LOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d",
//pContext->pBundledContext->NumberEffectsEnabled,
//pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
if(status == -ENODATA){
- //LOGV("\tLVM_ERROR : Effect_process() actually processing last frame");
+ LOGV("\tEffect_process() processing last frame");
}
pContext->pBundledContext->NumberEffectsCalled = 0;
/* Process all the available frames, block processing is
@@ -2836,10 +2879,10 @@ extern "C" int Effect_command(effect_interface_t self,
case EFFECT_CMD_SET_PARAM:{
//LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
if(pContext->EffectType == LVM_BASS_BOOST){
- //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d ",
- // *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
- // *replySize,
- // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
+ //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d",
+ // *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
+ // *replySize,
+ // *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
if (pCmdData == NULL||
cmdSize != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))||
@@ -3038,30 +3081,71 @@ extern "C" int Effect_command(effect_interface_t self,
}
case EFFECT_CMD_SET_VOLUME:
{
- int32_t vol = *(int32_t *)pCmdData;
- int16_t dB;
- int32_t vol_ret[2] = {1<<24,1<<24}; // Apply no volume
+ uint32_t leftVolume, rightVolume;
+ int16_t leftdB, rightdB;
+ int16_t maxdB, pandB;
+ int32_t vol_ret[2] = {1<<24,1<<24}; // Apply no volume
+ int status = 0;
+ LVM_ControlParams_t ActiveParams; /* Current control Parameters */
+ LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */
// if pReplyData is NULL, VOL_CTRL is delegated to another effect
if(pReplyData == LVM_NULL){
break;
}
- if(vol==0x1000000){
- vol -= 1;
+ if (pCmdData == NULL ||
+ cmdSize != 2 * sizeof(uint32_t)) {
+ LOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
+ "EFFECT_CMD_SET_VOLUME: ERROR");
+ return -EINVAL;
}
- // Convert volume linear (Q8.24) to volume dB (0->-96)
- dB = android::LVC_ToDB_s32Tos16(vol <<7);
- dB = (dB +8)>>4;
- dB = (dB <-96) ? -96 : dB ;
- LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
- "effect is %d",
- pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
- (int32_t)dB, vol<<7, pContext->EffectType);
+ leftVolume = ((*(uint32_t *)pCmdData));
+ rightVolume = ((*((uint32_t *)pCmdData + 1)));
+
+ if(leftVolume == 0x1000000){
+ leftVolume -= 1;
+ }
+ if(rightVolume == 0x1000000){
+ rightVolume -= 1;
+ }
+
+ // Convert volume to dB
+ leftdB = android::LVC_Convert_VolToDb(leftVolume);
+ rightdB = android::LVC_Convert_VolToDb(rightVolume);
+
+ pandB = rightdB - leftdB;
+
+ // Calculate max volume in dB
+ maxdB = leftdB;
+ if(rightdB > maxdB){
+ maxdB = rightdB;
+ }
+ //LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
+ // "effect is %d",
+ //pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
+ //(int32_t)maxdB, maxVol<<7, pContext->EffectType);
+ //LOGV("\tEFFECT_CMD_SET_VOLUME: Left is %d, Right is %d", leftVolume, rightVolume);
+ //LOGV("\tEFFECT_CMD_SET_VOLUME: Left %ddB, Right %ddB, Position %ddB",
+ // leftdB, rightdB, pandB);
memcpy(pReplyData, vol_ret, sizeof(int32_t)*2);
- android::VolumeSetVolumeLevel(pContext, (int16_t)(dB*100));
+ android::VolumeSetVolumeLevel(pContext, (int16_t)(maxdB*100));
+
+ /* Get the current settings */
+ LvmStatus =LVM_GetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams);
+ LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeSetStereoPosition")
+ if(LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+ /* Volume parameters */
+ ActiveParams.VC_Balance = pandB;
+ LOGV("\t\tVolumeSetStereoPosition() (-96dB -> +96dB)-> %d\n", ActiveParams.VC_Balance );
+
+ /* Activate the initial settings */
+ LvmStatus =LVM_SetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams);
+ LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "VolumeSetStereoPosition")
+ if(LvmStatus != LVM_SUCCESS) return -EINVAL;
break;
}
case EFFECT_CMD_SET_AUDIO_MODE:
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 91963af..2b51029 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -88,12 +88,13 @@ struct BundledEffectContext{
int positionSaved;
bool bMuteEnabled; /* Must store as mute = -96dB level */
bool bStereoPositionEnabled;
- int frameCount;
LVM_Fs_en SampleRate;
int SamplesPerSecond;
int SamplesToExitCountEq;
int SamplesToExitCountBb;
int SamplesToExitCountVirt;
+ LVM_INT16 *workBuffer;
+ int frameCount;
#ifdef LVM_PCM
FILE *PcmInPtr;
FILE *PcmOutPtr;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index aba5f52..d975cb9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -534,8 +534,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
if (f) {
while (!feof(f)) {
fgets(buffer, SIZE, f);
- if (strstr(buffer, " /sdcard/") ||
+ if (strstr(buffer, " /mnt/sdcard/") ||
strstr(buffer, " /system/sounds/") ||
+ strstr(buffer, " /data/") ||
strstr(buffer, " /system/media/")) {
result.append(" ");
result.append(buffer);
@@ -569,8 +570,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
} else {
linkto[len] = 0;
}
- if (strstr(linkto, "/sdcard/") == linkto ||
+ if (strstr(linkto, "/mnt/sdcard/") == linkto ||
strstr(linkto, "/system/sounds/") == linkto ||
+ strstr(linkto, "/data/") == linkto ||
strstr(linkto, "/system/media/") == linkto) {
result.append(" ");
result.append(buffer);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e0321a5..3e17a7e 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -16,6 +16,7 @@ LOCAL_SRC_FILES:= \
HTTPStream.cpp \
JPEGSource.cpp \
MP3Extractor.cpp \
+ MPEG2TSWriter.cpp \
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
MediaBuffer.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index c27cfc8..b314114 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -27,9 +27,13 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
+#include "include/AwesomePlayer.h"
+
namespace android {
-AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
+AudioPlayer::AudioPlayer(
+ const sp<MediaPlayerBase::AudioSink> &audioSink,
+ AwesomePlayer *observer)
: mAudioTrack(NULL),
mInputBuffer(NULL),
mSampleRate(0),
@@ -45,7 +49,8 @@ AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
mIsFirstBuffer(false),
mFirstBufferResult(OK),
mFirstBuffer(NULL),
- mAudioSink(audioSink) {
+ mAudioSink(audioSink),
+ mObserver(observer) {
}
AudioPlayer::~AudioPlayer() {
@@ -301,6 +306,9 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
}
mSeeking = false;
+ if (mObserver) {
+ mObserver->postAudioSeekComplete();
+ }
}
}
@@ -323,6 +331,10 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
if (err != OK) {
+ if (mObserver && !mReachedEOS) {
+ mObserver->postAudioEOS();
+ }
+
mReachedEOS = true;
mFinalStatus = err;
break;
@@ -411,6 +423,12 @@ status_t AudioPlayer::seekTo(int64_t time_us) {
mReachedEOS = false;
mSeekTimeUs = time_us;
+ if (mAudioSink != NULL) {
+ mAudioSink->flush();
+ } else {
+ mAudioTrack->flush();
+ }
+
return OK;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8507afc..12022bd 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -639,7 +639,7 @@ status_t AwesomePlayer::play_l() {
if (mAudioSource != NULL) {
if (mAudioPlayer == NULL) {
if (mAudioSink != NULL) {
- mAudioPlayer = new AudioPlayer(mAudioSink);
+ mAudioPlayer = new AudioPlayer(mAudioSink, this);
mAudioPlayer->setSource(mAudioSource);
// We've already started the MediaSource in order to enable
@@ -666,8 +666,6 @@ status_t AwesomePlayer::play_l() {
} else {
mAudioPlayer->resume();
}
-
- postCheckAudioStatusEvent_l();
}
if (mTimeSource == NULL && mAudioPlayer == NULL) {
@@ -1169,7 +1167,7 @@ void AwesomePlayer::postCheckAudioStatusEvent_l() {
return;
}
mAudioStatusEventPending = true;
- mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
+ mQueue.postEvent(mCheckAudioStatusEvent);
}
void AwesomePlayer::onCheckAudioStatus() {
@@ -1200,8 +1198,6 @@ void AwesomePlayer::onCheckAudioStatus() {
mFlags |= FIRST_FRAME;
postStreamDoneEvent_l(finalStatus);
}
-
- postCheckAudioStatusEvent_l();
}
status_t AwesomePlayer::prepare() {
@@ -1662,5 +1658,13 @@ uint32_t AwesomePlayer::flags() const {
return mExtractorFlags;
}
+void AwesomePlayer::postAudioEOS() {
+ postCheckAudioStatusEvent_l();
+}
+
+void AwesomePlayer::postAudioSeekComplete() {
+ postCheckAudioStatusEvent_l();
+}
+
} // namespace android
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
new file mode 100644
index 0000000..ee74b88
--- /dev/null
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -0,0 +1,758 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG2TSWriter"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include "include/ESDS.h"
+
+namespace android {
+
+struct MPEG2TSWriter::SourceInfo : public AHandler {
+ SourceInfo(const sp<MediaSource> &source);
+
+ void start(const sp<AMessage> &notify);
+ void stop();
+
+ unsigned streamType() const;
+ unsigned incrementContinuityCounter();
+
+ enum {
+ kNotifyStartFailed,
+ kNotifyBuffer,
+ kNotifyReachedEOS,
+ };
+
+protected:
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
+ virtual ~SourceInfo();
+
+private:
+ enum {
+ kWhatStart = 'strt',
+ kWhatRead = 'read',
+ };
+
+ sp<MediaSource> mSource;
+ sp<ALooper> mLooper;
+ sp<AMessage> mNotify;
+
+ sp<ABuffer> mAACBuffer;
+
+ unsigned mStreamType;
+ unsigned mContinuityCounter;
+
+ void extractCodecSpecificData();
+
+ void appendAACFrames(MediaBuffer *buffer);
+ void flushAACFrames();
+
+ void postAVCFrame(MediaBuffer *buffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
+};
+
+MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source)
+ : mSource(source),
+ mLooper(new ALooper),
+ mStreamType(0),
+ mContinuityCounter(0) {
+ mLooper->setName("MPEG2TSWriter source");
+
+ sp<MetaData> meta = mSource->getFormat();
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+ mStreamType = 0x0f;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ mStreamType = 0x1b;
+ } else {
+ TRESPASS();
+ }
+}
+
+MPEG2TSWriter::SourceInfo::~SourceInfo() {
+}
+
+unsigned MPEG2TSWriter::SourceInfo::streamType() const {
+ return mStreamType;
+}
+
+unsigned MPEG2TSWriter::SourceInfo::incrementContinuityCounter() {
+ if (++mContinuityCounter == 16) {
+ mContinuityCounter = 0;
+ }
+
+ return mContinuityCounter;
+}
+
+void MPEG2TSWriter::SourceInfo::start(const sp<AMessage> &notify) {
+ mLooper->registerHandler(this);
+ mLooper->start();
+
+ mNotify = notify;
+
+ (new AMessage(kWhatStart, id()))->post();
+}
+
+void MPEG2TSWriter::SourceInfo::stop() {
+ mLooper->unregisterHandler(id());
+ mLooper->stop();
+}
+
+void MPEG2TSWriter::SourceInfo::extractCodecSpecificData() {
+ sp<MetaData> meta = mSource->getFormat();
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ return;
+ }
+
+ sp<ABuffer> out = new ABuffer(1024);
+ out->setRange(0, 0);
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ CHECK(meta->findData(kKeyAVCC, &type, &data, &size));
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ size_t numSeqParameterSets = ptr[5] & 31;
+
+ ptr += 6;
+ size -= 6;
+
+ for (size_t i = 0; i < numSeqParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ CHECK_LE(out->size() + 4 + length, out->capacity());
+ memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4);
+ memcpy(out->data() + out->size() + 4, ptr, length);
+ out->setRange(0, out->size() + length + 4);
+
+ ptr += length;
+ size -= length;
+ }
+
+ CHECK(size >= 1);
+ size_t numPictureParameterSets = *ptr;
+ ++ptr;
+ --size;
+
+ for (size_t i = 0; i < numPictureParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ CHECK_LE(out->size() + 4 + length, out->capacity());
+ memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4);
+ memcpy(out->data() + out->size() + 4, ptr, length);
+ out->setRange(0, out->size() + length + 4);
+
+ ptr += length;
+ size -= length;
+ }
+
+ out->meta()->setInt64("timeUs", 0ll);
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kNotifyBuffer);
+ notify->setObject("buffer", out);
+ notify->post();
+}
+
+void MPEG2TSWriter::SourceInfo::postAVCFrame(MediaBuffer *buffer) {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kNotifyBuffer);
+
+ sp<ABuffer> copy =
+ new ABuffer(buffer->range_length());
+ memcpy(copy->data(),
+ (const uint8_t *)buffer->data()
+ + buffer->range_offset(),
+ buffer->range_length());
+
+ int64_t timeUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+ copy->meta()->setInt64("timeUs", timeUs);
+
+ int32_t isSync;
+ if (buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)
+ && isSync != 0) {
+ copy->meta()->setInt32("isSync", true);
+ }
+
+ notify->setObject("buffer", copy);
+ notify->post();
+}
+
+void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBuffer *buffer) {
+ if (mAACBuffer != NULL
+ && mAACBuffer->size() + 7 + buffer->range_length()
+ > mAACBuffer->capacity()) {
+ flushAACFrames();
+ }
+
+ if (mAACBuffer == NULL) {
+ size_t alloc = 4096;
+ if (buffer->range_length() + 7 > alloc) {
+ alloc = 7 + buffer->range_length();
+ }
+
+ mAACBuffer = new ABuffer(alloc);
+
+ int64_t timeUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+
+ mAACBuffer->meta()->setInt64("timeUs", timeUs);
+ mAACBuffer->meta()->setInt32("isSync", true);
+
+ mAACBuffer->setRange(0, 0);
+ }
+
+ sp<MetaData> meta = mSource->getFormat();
+ uint32_t type;
+ const void *data;
+ size_t size;
+ CHECK(meta->findData(kKeyESDS, &type, &data, &size));
+
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), (status_t)OK);
+
+ const uint8_t *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
+ (const void **)&codec_specific_data, &codec_specific_data_size);
+
+ CHECK_GE(codec_specific_data_size, 2u);
+
+ unsigned profile = (codec_specific_data[0] >> 3) - 1;
+
+ unsigned sampling_freq_index =
+ ((codec_specific_data[0] & 7) << 1)
+ | (codec_specific_data[1] >> 7);
+
+ unsigned channel_configuration =
+ (codec_specific_data[1] >> 3) & 0x0f;
+
+ uint8_t *ptr = mAACBuffer->data() + mAACBuffer->size();
+
+ const uint32_t aac_frame_length = buffer->range_length() + 7;
+
+ *ptr++ = 0xff;
+ *ptr++ = 0xf1; // b11110001, ID=0, layer=0, protection_absent=1
+
+ *ptr++ =
+ profile << 6
+ | sampling_freq_index << 2
+ | ((channel_configuration >> 2) & 1); // private_bit=0
+
+ // original_copy=0, home=0, copyright_id_bit=0, copyright_id_start=0
+ *ptr++ =
+ (channel_configuration & 3) << 6
+ | aac_frame_length >> 11;
+ *ptr++ = (aac_frame_length >> 3) & 0xff;
+ *ptr++ = (aac_frame_length & 7) << 5;
+
+ // adts_buffer_fullness=0, number_of_raw_data_blocks_in_frame=0
+ *ptr++ = 0;
+
+ memcpy(ptr,
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ buffer->range_length());
+
+ ptr += buffer->range_length();
+
+ mAACBuffer->setRange(0, ptr - mAACBuffer->data());
+}
+
+void MPEG2TSWriter::SourceInfo::flushAACFrames() {
+ if (mAACBuffer == NULL) {
+ return;
+ }
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kNotifyBuffer);
+ notify->setObject("buffer", mAACBuffer);
+ notify->post();
+
+ mAACBuffer.clear();
+}
+
+void MPEG2TSWriter::SourceInfo::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatStart:
+ {
+ status_t err = mSource->start();
+ if (err != OK) {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kNotifyStartFailed);
+ notify->post();
+ break;
+ }
+
+ extractCodecSpecificData();
+
+ (new AMessage(kWhatRead, id()))->post();
+ break;
+ }
+
+ case kWhatRead:
+ {
+ MediaBuffer *buffer;
+ status_t err = mSource->read(&buffer);
+
+ if (err != OK && err != INFO_FORMAT_CHANGED) {
+ if (mStreamType == 0x0f) {
+ flushAACFrames();
+ }
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kNotifyReachedEOS);
+ notify->setInt32("status", err);
+ notify->post();
+ break;
+ }
+
+ if (err == OK) {
+ if (buffer->range_length() > 0) {
+ if (mStreamType == 0x0f) {
+ appendAACFrames(buffer);
+ } else {
+ postAVCFrame(buffer);
+ }
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ msg->post();
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2TSWriter::MPEG2TSWriter(const char *filename)
+ : mFile(fopen(filename, "wb")),
+ mStarted(false),
+ mNumSourcesDone(0),
+ mNumTSPacketsWritten(0),
+ mNumTSPacketsBeforeMeta(0) {
+ CHECK(mFile != NULL);
+
+ mLooper = new ALooper;
+ mLooper->setName("MPEG2TSWriter");
+
+ mReflector = new AHandlerReflector<MPEG2TSWriter>(this);
+
+ mLooper->registerHandler(mReflector);
+ mLooper->start();
+}
+
+MPEG2TSWriter::~MPEG2TSWriter() {
+ mLooper->unregisterHandler(mReflector->id());
+ mLooper->stop();
+
+ fclose(mFile);
+ mFile = NULL;
+}
+
+status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) {
+ CHECK(!mStarted);
+
+ sp<MetaData> meta = source->getFormat();
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+ && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ sp<SourceInfo> info = new SourceInfo(source);
+
+ mSources.push(info);
+
+ return OK;
+}
+
+status_t MPEG2TSWriter::start(MetaData *param) {
+ CHECK(!mStarted);
+
+ mStarted = true;
+ mNumSourcesDone = 0;
+ mNumTSPacketsWritten = 0;
+ mNumTSPacketsBeforeMeta = 0;
+
+ for (size_t i = 0; i < mSources.size(); ++i) {
+ sp<AMessage> notify =
+ new AMessage(kWhatSourceNotify, mReflector->id());
+
+ notify->setInt32("source-index", i);
+
+ mSources.editItemAt(i)->start(notify);
+ }
+
+ return OK;
+}
+
+status_t MPEG2TSWriter::stop() {
+ CHECK(mStarted);
+
+ for (size_t i = 0; i < mSources.size(); ++i) {
+ mSources.editItemAt(i)->stop();
+ }
+ mStarted = false;
+
+ return OK;
+}
+
+status_t MPEG2TSWriter::pause() {
+ CHECK(mStarted);
+
+ return OK;
+}
+
+bool MPEG2TSWriter::reachedEOS() {
+ return !mStarted || (mNumSourcesDone == mSources.size() ? true : false);
+}
+
+status_t MPEG2TSWriter::dump(int fd, const Vector<String16> &args) {
+ return OK;
+}
+
+void MPEG2TSWriter::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatSourceNotify:
+ {
+ int32_t sourceIndex;
+ CHECK(msg->findInt32("source-index", &sourceIndex));
+
+ int32_t what;
+ CHECK(msg->findInt32("what", &what));
+
+ if (what == SourceInfo::kNotifyReachedEOS
+ || what == SourceInfo::kNotifyStartFailed) {
+ ++mNumSourcesDone;
+ } else if (what == SourceInfo::kNotifyBuffer) {
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+
+ writeTS();
+
+ sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
+ writeAccessUnit(sourceIndex, buffer);
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+void MPEG2TSWriter::writeProgramAssociationTable() {
+ // 0x47
+ // transport_error_indicator = b0
+ // payload_unit_start_indicator = b1
+ // transport_priority = b0
+ // PID = b0000000000000 (13 bits)
+ // transport_scrambling_control = b00
+ // adaptation_field_control = b01 (no adaptation field, payload only)
+ // continuity_counter = b????
+ // skip = 0x00
+ // --- payload follows
+ // table_id = 0x00
+ // section_syntax_indicator = b1
+ // must_be_zero = b0
+ // reserved = b11
+ // section_length = 0x00d
+ // transport_stream_id = 0x0000
+ // reserved = b11
+ // version_number = b00001
+ // current_next_indicator = b1
+ // section_number = 0x00
+ // last_section_number = 0x00
+ // one program follows:
+ // program_number = 0x0001
+ // reserved = b111
+ // program_map_PID = 0x01e0 (13 bits!)
+ // CRC = 0x????????
+
+ static const uint8_t kData[] = {
+ 0x47,
+ 0x40, 0x00, 0x10, 0x00, // b0100 0000 0000 0000 0001 ???? 0000 0000
+ 0x00, 0xb0, 0x0d, 0x00, // b0000 0000 1011 0000 0000 1101 0000 0000
+ 0x00, 0xc3, 0x00, 0x00, // b0000 0000 1100 0011 0000 0000 0000 0000
+ 0x00, 0x01, 0xe1, 0xe0, // b0000 0000 0000 0001 1110 0001 1110 0000
+ 0x00, 0x00, 0x00, 0x00 // b???? ???? ???? ???? ???? ???? ???? ????
+ };
+
+ sp<ABuffer> buffer = new ABuffer(188);
+ memset(buffer->data(), 0, buffer->size());
+ memcpy(buffer->data(), kData, sizeof(kData));
+
+ static const unsigned kContinuityCounter = 5;
+ buffer->data()[3] |= kContinuityCounter;
+
+ CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
+}
+
+void MPEG2TSWriter::writeProgramMap() {
+ // 0x47
+ // transport_error_indicator = b0
+ // payload_unit_start_indicator = b1
+ // transport_priority = b0
+ // PID = b0 0001 1110 0000 (13 bits) [0x1e0]
+ // transport_scrambling_control = b00
+ // adaptation_field_control = b01 (no adaptation field, payload only)
+ // continuity_counter = b????
+ // skip = 0x00
+ // -- payload follows
+ // table_id = 0x02
+ // section_syntax_indicator = b1
+ // must_be_zero = b0
+ // reserved = b11
+ // section_length = 0x???
+ // program_number = 0x0001
+ // reserved = b11
+ // version_number = b00001
+ // current_next_indicator = b1
+ // section_number = 0x00
+ // last_section_number = 0x00
+ // reserved = b111
+ // PCR_PID = b? ???? ???? ???? (13 bits)
+ // reserved = b1111
+ // program_info_length = 0x000
+ // one or more elementary stream descriptions follow:
+ // stream_type = 0x??
+ // reserved = b111
+ // elementary_PID = b? ???? ???? ???? (13 bits)
+ // reserved = b1111
+ // ES_info_length = 0x000
+ // CRC = 0x????????
+
+ static const uint8_t kData[] = {
+ 0x47,
+ 0x41, 0xe0, 0x10, 0x00, // b0100 0001 1110 0000 0001 ???? 0000 0000
+ 0x02, 0xb0, 0x00, 0x00, // b0000 0010 1011 ???? ???? ???? 0000 0000
+ 0x01, 0xc3, 0x00, 0x00, // b0000 0001 1100 0011 0000 0000 0000 0000
+ 0xe0, 0x00, 0xf0, 0x00 // b111? ???? ???? ???? 1111 0000 0000 0000
+ };
+
+ sp<ABuffer> buffer = new ABuffer(188);
+ memset(buffer->data(), 0, buffer->size());
+ memcpy(buffer->data(), kData, sizeof(kData));
+
+ static const unsigned kContinuityCounter = 5;
+ buffer->data()[3] |= kContinuityCounter;
+
+ size_t section_length = 5 * mSources.size() + 4 + 9;
+ buffer->data()[6] |= section_length >> 8;
+ buffer->data()[7] = section_length & 0xff;
+
+ static const unsigned kPCR_PID = 0x1e1;
+ buffer->data()[13] |= (kPCR_PID >> 8) & 0x1f;
+ buffer->data()[14] = kPCR_PID & 0xff;
+
+ uint8_t *ptr = &buffer->data()[sizeof(kData)];
+ for (size_t i = 0; i < mSources.size(); ++i) {
+ *ptr++ = mSources.editItemAt(i)->streamType();
+
+ const unsigned ES_PID = 0x1e0 + i + 1;
+ *ptr++ = 0xe0 | (ES_PID >> 8);
+ *ptr++ = ES_PID & 0xff;
+ *ptr++ = 0xf0;
+ *ptr++ = 0x00;
+ }
+
+ *ptr++ = 0x00;
+ *ptr++ = 0x00;
+ *ptr++ = 0x00;
+ *ptr++ = 0x00;
+
+ CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
+}
+
+void MPEG2TSWriter::writeAccessUnit(
+ int32_t sourceIndex, const sp<ABuffer> &accessUnit) {
+ // 0x47
+ // transport_error_indicator = b0
+ // payload_unit_start_indicator = b1
+ // transport_priority = b0
+ // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
+ // transport_scrambling_control = b00
+ // adaptation_field_control = b01 (no adaptation field, payload only)
+ // continuity_counter = b????
+ // -- payload follows
+ // packet_startcode_prefix = 0x000001
+ // stream_id = 0x?? (0xe0 for avc video, 0xc0 for aac audio)
+ // PES_packet_length = 0x????
+ // reserved = b10
+ // PES_scrambling_control = b00
+ // PES_priority = b0
+ // data_alignment_indicator = b1
+ // copyright = b0
+ // original_or_copy = b0
+ // PTS_DTS_flags = b10 (PTS only)
+ // ESCR_flag = b0
+ // ES_rate_flag = b0
+ // DSM_trick_mode_flag = b0
+ // additional_copy_info_flag = b0
+ // PES_CRC_flag = b0
+ // PES_extension_flag = b0
+ // PES_header_data_length = 0x05
+ // reserved = b0010 (PTS)
+ // PTS[32..30] = b???
+ // reserved = b1
+ // PTS[29..15] = b??? ???? ???? ???? (15 bits)
+ // reserved = b1
+ // PTS[14..0] = b??? ???? ???? ???? (15 bits)
+ // reserved = b1
+ // the first fragment of "buffer" follows
+
+ sp<ABuffer> buffer = new ABuffer(188);
+ memset(buffer->data(), 0, buffer->size());
+
+ const unsigned PID = 0x1e0 + sourceIndex + 1;
+
+ const unsigned continuity_counter =
+ mSources.editItemAt(sourceIndex)->incrementContinuityCounter();
+
+ // XXX if there are multiple streams of a kind (more than 1 audio or
+ // more than 1 video) they need distinct stream_ids.
+ const unsigned stream_id =
+ mSources.editItemAt(sourceIndex)->streamType() == 0x0f ? 0xc0 : 0xe0;
+
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+ uint32_t PTS = (timeUs * 9ll) / 100ll;
+
+ size_t PES_packet_length = accessUnit->size() + 8;
+
+ uint8_t *ptr = buffer->data();
+ *ptr++ = 0x47;
+ *ptr++ = 0x40 | (PID >> 8);
+ *ptr++ = PID & 0xff;
+ *ptr++ = 0x10 | continuity_counter;
+ *ptr++ = 0x00;
+ *ptr++ = 0x00;
+ *ptr++ = 0x01;
+ *ptr++ = stream_id;
+ *ptr++ = PES_packet_length >> 8;
+ *ptr++ = PES_packet_length & 0xff;
+ *ptr++ = 0x84;
+ *ptr++ = 0x80;
+ *ptr++ = 0x05;
+ *ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1;
+ *ptr++ = (PTS >> 22) & 0xff;
+ *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1;
+ *ptr++ = (PTS >> 7) & 0xff;
+ *ptr++ = ((PTS & 0x7f) << 1) | 1;
+
+ size_t sizeLeft = buffer->data() + buffer->size() - ptr;
+ size_t copy = accessUnit->size();
+ if (copy > sizeLeft) {
+ copy = sizeLeft;
+ }
+
+ memcpy(ptr, accessUnit->data(), copy);
+
+ CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
+
+ size_t offset = copy;
+ while (offset < accessUnit->size()) {
+ // for subsequent fragments of "buffer":
+ // 0x47
+ // transport_error_indicator = b0
+ // payload_unit_start_indicator = b0
+ // transport_priority = b0
+ // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
+ // transport_scrambling_control = b00
+ // adaptation_field_control = b01 (no adaptation field, payload only)
+ // continuity_counter = b????
+ // the fragment of "buffer" follows.
+
+ memset(buffer->data(), 0, buffer->size());
+
+ const unsigned continuity_counter =
+ mSources.editItemAt(sourceIndex)->incrementContinuityCounter();
+
+ ptr = buffer->data();
+ *ptr++ = 0x47;
+ *ptr++ = 0x00 | (PID >> 8);
+ *ptr++ = PID & 0xff;
+ *ptr++ = 0x10 | continuity_counter;
+
+ size_t sizeLeft = buffer->data() + buffer->size() - ptr;
+ size_t copy = accessUnit->size() - offset;
+ if (copy > sizeLeft) {
+ copy = sizeLeft;
+ }
+
+ memcpy(ptr, accessUnit->data() + offset, copy);
+ CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile),
+ buffer->size());
+
+ offset += copy;
+ }
+}
+
+void MPEG2TSWriter::writeTS() {
+ if (mNumTSPacketsWritten >= mNumTSPacketsBeforeMeta) {
+ writeProgramAssociationTable();
+ writeProgramMap();
+
+ mNumTSPacketsBeforeMeta = mNumTSPacketsWritten + 2500;
+ }
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 7a8cf32..43938b2 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -93,7 +93,10 @@ private:
sp<DataSource> mSource;
off_t mOffset;
Page mCurrentPage;
+ uint64_t mPrevGranulePosition;
size_t mCurrentPageSize;
+ bool mFirstPacketInPage;
+ uint64_t mCurrentPageSamples;
size_t mNextLaceIndex;
off_t mFirstDataOffset;
@@ -113,6 +116,8 @@ private:
void parseFileMetaData();
void extractAlbumArt(const void *data, size_t size);
+ uint64_t findPrevGranulePosition(off_t pageOffset);
+
MyVorbisExtractor(const MyVorbisExtractor &);
MyVorbisExtractor &operator=(const MyVorbisExtractor &);
};
@@ -193,7 +198,10 @@ status_t OggSource::read(
MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
: mSource(source),
mOffset(0),
+ mPrevGranulePosition(0),
mCurrentPageSize(0),
+ mFirstPacketInPage(true),
+ mCurrentPageSamples(0),
mNextLaceIndex(0),
mFirstDataOffset(-1) {
mCurrentPage.mNumSegments = 0;
@@ -238,6 +246,52 @@ status_t MyVorbisExtractor::findNextPage(
}
}
+// Given the offset of the "current" page, find the page immediately preceding
+// it (if any) and return its granule position.
+// To do this we back up from the "current" page's offset until we find any
+// page preceding it and then scan forward to just before the current page.
+uint64_t MyVorbisExtractor::findPrevGranulePosition(off_t pageOffset) {
+ off_t prevPageOffset = 0;
+ off_t prevGuess = pageOffset;
+ for (;;) {
+ if (prevGuess >= 5000) {
+ prevGuess -= 5000;
+ } else {
+ prevGuess = 0;
+ }
+
+ LOGV("backing up %ld bytes", pageOffset - prevGuess);
+
+ CHECK_EQ(findNextPage(prevGuess, &prevPageOffset), (status_t)OK);
+
+ if (prevPageOffset < pageOffset || prevGuess == 0) {
+ break;
+ }
+ }
+
+ if (prevPageOffset == pageOffset) {
+ // We did not find a page preceding this one.
+ return 0;
+ }
+
+ LOGV("prevPageOffset at %ld, pageOffset at %ld", prevPageOffset, pageOffset);
+
+ for (;;) {
+ Page prevPage;
+ ssize_t n = readPage(prevPageOffset, &prevPage);
+
+ if (n <= 0) {
+ return 0;
+ }
+
+ prevPageOffset += n;
+
+ if (prevPageOffset == pageOffset) {
+ return prevPage.mGranulePosition;
+ }
+ }
+}
+
status_t MyVorbisExtractor::seekToOffset(off_t offset) {
if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
// Once we know where the actual audio data starts (past the headers)
@@ -252,9 +306,16 @@ status_t MyVorbisExtractor::seekToOffset(off_t offset) {
return err;
}
+ // We found the page we wanted to seek to, but we'll also need
+ // the page preceding it to determine how many valid samples are on
+ // this page.
+ mPrevGranulePosition = findPrevGranulePosition(pageOffset);
+
mOffset = pageOffset;
mCurrentPageSize = 0;
+ mFirstPacketInPage = true;
+ mCurrentPageSamples = 0;
mCurrentPage.mNumSegments = 0;
mNextLaceIndex = 0;
@@ -399,6 +460,12 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
buffer->meta_data()->setInt64(kKeyTime, timeUs);
}
+ if (mFirstPacketInPage) {
+ buffer->meta_data()->setInt32(
+ kKeyValidSamples, mCurrentPageSamples);
+ mFirstPacketInPage = false;
+ }
+
*out = buffer;
return OK;
@@ -423,6 +490,12 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
}
+ mCurrentPageSamples =
+ mCurrentPage.mGranulePosition - mPrevGranulePosition;
+ mFirstPacketInPage = true;
+
+ mPrevGranulePosition = mCurrentPage.mGranulePosition;
+
mCurrentPageSize = n;
mNextLaceIndex = 0;
@@ -435,6 +508,10 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
buffer->meta_data()->setInt64(kKeyTime, timeUs);
}
+ buffer->meta_data()->setInt32(
+ kKeyValidSamples, mCurrentPageSamples);
+ mFirstPacketInPage = false;
+
*out = buffer;
return OK;
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index e4ed5e6..f58c16d 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -171,6 +171,10 @@ status_t AACDecoder::read(
mInputBuffer->release();
mInputBuffer = NULL;
}
+
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+ PVMP4AudioDecoderResetBuffer(mDecoderBuf);
} else {
seekTimeUs = -1;
}
diff --git a/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h b/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h
index 0620367..3ebd929 100644
--- a/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h
+++ b/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h
@@ -87,22 +87,22 @@ extern "C"
enum Frame_Type_3GPP
{
- AMR_475 = 0,
- AMR_515,
- AMR_59,
- AMR_67,
- AMR_74,
- AMR_795,
- AMR_102,
- AMR_122,
- AMR_SID,
- GSM_EFR_SID,
- TDMA_EFR_SID,
- PDC_EFR_SID,
- FOR_FUTURE_USE1,
- FOR_FUTURE_USE2,
- FOR_FUTURE_USE3,
- AMR_NO_DATA
+ AMR_475 = 0, /* 4.75 kbps */
+ AMR_515, /* 5.15 kbps */
+ AMR_59, /* 5.9 kbps */
+ AMR_67, /* 6.7 kbps */
+ AMR_74, /* 7.4 kbps */
+ AMR_795, /* 7.95 kbps */
+ AMR_102, /* 10.2 kbps */
+ AMR_122, /* 12.2 kbps */
+ AMR_SID, /* GSM AMR DTX */
+ GSM_EFR_SID, /* GSM EFR DTX */
+ TDMA_EFR_SID, /* TDMA EFR DTX */
+ PDC_EFR_SID, /* PDC EFR DTX */
+ FOR_FUTURE_USE1, /* Unused 1 */
+ FOR_FUTURE_USE2, /* Unused 2 */
+ FOR_FUTURE_USE3, /* Unused 3 */
+ AMR_NO_DATA /* No data */
};
/*----------------------------------------------------------------------------
diff --git a/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h b/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h
index 673a94a..a9fdb1c 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h
+++ b/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h
@@ -87,6 +87,8 @@ terms listed above has been obtained from the copyright holder.
#include "gsm_amr_typedefs.h"
#include "pvamrnbdecoder_api.h"
+#include "frame_type_3gpp.h"
+
/*--------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C"
@@ -117,25 +119,6 @@ extern "C"
/*----------------------------------------------------------------------------
; ENUMERATED TYPEDEF'S
----------------------------------------------------------------------------*/
- enum Frame_Type_3GPP
- {
- AMR_475 = 0, /* 4.75 kbps */
- AMR_515, /* 5.15 kbps */
- AMR_59, /* 5.9 kbps */
- AMR_67, /* 6.7 kbps */
- AMR_74, /* 7.4 kbps */
- AMR_795, /* 7.95 kbps */
- AMR_102, /* 10.2 kbps */
- AMR_122, /* 12.2 kbps */
- AMR_SID, /* GSM AMR DTX */
- GSM_EFR_SID, /* GSM EFR DTX */
- TDMA_EFR_SID, /* TDMA EFR DTX */
- PDC_EFR_SID, /* PDC EFR DTX */
- FOR_FUTURE_USE1, /* Unused 1 */
- FOR_FUTURE_USE2, /* Unused 2 */
- FOR_FUTURE_USE3, /* Unused 3 */
- AMR_NO_DATA
- }; /* No data */
/*----------------------------------------------------------------------------
; STRUCTURES TYPEDEF'S
diff --git a/media/libstagefright/codecs/amrnb/enc/src/gsmamr_enc.h b/media/libstagefright/codecs/amrnb/enc/src/gsmamr_enc.h
index 390a44d..67c7aa3 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/gsmamr_enc.h
+++ b/media/libstagefright/codecs/amrnb/enc/src/gsmamr_enc.h
@@ -86,6 +86,7 @@ terms listed above has been obtained from the copyright holder.
----------------------------------------------------------------------------*/
#include "gsm_amr_typedefs.h"
+#include "frame_type_3gpp.h"
/*--------------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -137,26 +138,6 @@ extern "C"
N_MODES /* Not Used */
};
- enum Frame_Type_3GPP
- {
- AMR_475 = 0, /* 4.75 kbps */
- AMR_515, /* 5.15 kbps */
- AMR_59, /* 5.9 kbps */
- AMR_67, /* 6.7 kbps */
- AMR_74, /* 7.4 kbps */
- AMR_795, /* 7.95 kbps */
- AMR_102, /* 10.2 kbps */
- AMR_122, /* 12.2 kbps */
- AMR_SID, /* GSM AMR DTX */
- GSM_EFR_SID, /* GSM EFR DTX */
- TDMA_EFR_SID, /* TDMA EFR DTX */
- PDC_EFR_SID, /* PDC EFR DTX */
- FOR_FUTURE_USE1, /* Unused 1 */
- FOR_FUTURE_USE2, /* Unused 2 */
- FOR_FUTURE_USE3, /* Unused 3 */
- AMR_NO_DATA /* No data */
- };
-
/*----------------------------------------------------------------------------
; STRUCTURES TYPEDEF'S
----------------------------------------------------------------------------*/
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
index c4a8280..59dd740 100644
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -132,6 +132,10 @@ status_t MP3Decoder::read(
mInputBuffer->release();
mInputBuffer = NULL;
}
+
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
} else {
seekTimeUs = -1;
}
diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
index 53f0638..703b41e 100644
--- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VorbisDecoder"
+#include <utils/Log.h>
+
#include "VorbisDecoder.h"
#include <media/stagefright/MediaBufferGroup.h>
@@ -108,6 +112,7 @@ status_t VorbisDecoder::start(MetaData *params) {
mAnchorTimeUs = 0;
mNumFramesOutput = 0;
+ mNumFramesLeftOnPage = 0;
mStarted = true;
return OK;
@@ -188,6 +193,13 @@ int VorbisDecoder::decodePacket(MediaBuffer *packet, MediaBuffer *out) {
}
}
+ if (numFrames > mNumFramesLeftOnPage) {
+ LOGV("discarding %d frames at end of page",
+ numFrames - mNumFramesLeftOnPage);
+ numFrames = mNumFramesLeftOnPage;
+ }
+ mNumFramesLeftOnPage -= numFrames;
+
out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels);
return numFrames;
@@ -226,6 +238,12 @@ status_t VorbisDecoder::read(
CHECK(seekTimeUs < 0);
}
+ int32_t numPageSamples;
+ if (inputBuffer->meta_data()->findInt32(
+ kKeyValidSamples, &numPageSamples)) {
+ mNumFramesLeftOnPage = numPageSamples;
+ }
+
MediaBuffer *outputBuffer;
CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 1f3946c..600faca 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -92,6 +92,9 @@ struct AwesomePlayer {
// This is a mask of MediaExtractor::Flags.
uint32_t flags() const;
+ void postAudioEOS();
+ void postAudioSeekComplete();
+
private:
friend struct AwesomeEvent;
diff --git a/media/libstagefright/include/VorbisDecoder.h b/media/libstagefright/include/VorbisDecoder.h
index e9a488a..13e8b77 100644
--- a/media/libstagefright/include/VorbisDecoder.h
+++ b/media/libstagefright/include/VorbisDecoder.h
@@ -55,6 +55,7 @@ private:
int32_t mSampleRate;
int64_t mAnchorTimeUs;
int64_t mNumFramesOutput;
+ int32_t mNumFramesLeftOnPage;
vorbis_dsp_state *mState;
vorbis_info *mVi;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 9952783..47cca80 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -389,20 +389,23 @@ void ATSParser::Stream::parsePES(ABitReader *br) {
// ES data follows.
- onPayloadData(
- PTS_DTS_flags, PTS, DTS,
- br->data(), br->numBitsLeft() / 8);
-
if (PES_packet_length != 0) {
CHECK_GE(PES_packet_length, PES_header_data_length + 3);
unsigned dataLength =
PES_packet_length - 3 - PES_header_data_length;
- CHECK_EQ(br->numBitsLeft(), dataLength * 8);
+ CHECK_GE(br->numBitsLeft(), dataLength * 8);
+
+ onPayloadData(
+ PTS_DTS_flags, PTS, DTS, br->data(), dataLength);
br->skipBits(dataLength * 8);
} else {
+ onPayloadData(
+ PTS_DTS_flags, PTS, DTS,
+ br->data(), br->numBitsLeft() / 8);
+
size_t payloadSizeBits = br->numBitsLeft();
CHECK((payloadSizeBits % 8) == 0);
@@ -491,7 +494,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData(
CHECK(picParamSet != NULL);
buffer->setRange(stopOffset, size - stopOffset);
- LOGI("buffer has %d bytes left.", buffer->size());
+ LOGV("buffer has %d bytes left.", buffer->size());
size_t csdSize =
1 + 3 + 1 + 1
@@ -527,6 +530,8 @@ static bool getNextNALUnit(
const uint8_t *data = *_data;
size_t size = *_size;
+ // hexdump(data, size);
+
*nalStart = NULL;
*nalSize = 0;
@@ -572,18 +577,23 @@ static bool getNextNALUnit(
++offset;
}
- CHECK_LT(offset + 2, size);
-
*nalStart = &data[startOffset];
*nalSize = endOffset - startOffset;
- *_data = &data[offset];
- *_size = size - offset;
+ if (offset + 2 < size) {
+ *_data = &data[offset];
+ *_size = size - offset;
+ } else {
+ *_data = NULL;
+ *_size = 0;
+ }
return true;
}
sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) {
+ // hexdump(data, size);
+
const uint8_t *tmpData = data;
size_t tmpSize = size;
@@ -591,6 +601,7 @@ sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) {
const uint8_t *nalStart;
size_t nalSize;
while (getNextNALUnit(&tmpData, &tmpSize, &nalStart, &nalSize)) {
+ // hexdump(nalStart, nalSize);
totalSize += 4 + nalSize;
}
@@ -615,15 +626,15 @@ static sp<ABuffer> FindMPEG2ADTSConfig(
CHECK_EQ(br.getBits(2), 0u);
br.getBits(1); // protection_absent
unsigned profile = br.getBits(2);
- LOGI("profile = %u", profile);
+ LOGV("profile = %u", profile);
CHECK_NE(profile, 3u);
unsigned sampling_freq_index = br.getBits(4);
br.getBits(1); // private_bit
unsigned channel_configuration = br.getBits(3);
CHECK_NE(channel_configuration, 0u);
- LOGI("sampling_freq_index = %u", sampling_freq_index);
- LOGI("channel_configuration = %u", channel_configuration);
+ LOGV("sampling_freq_index = %u", sampling_freq_index);
+ LOGV("channel_configuration = %u", channel_configuration);
CHECK_LE(sampling_freq_index, 11u);
static const int32_t kSamplingFreq[] = {
@@ -707,8 +718,8 @@ void ATSParser::Stream::onPayloadData(
sp<ABuffer> csd =
FindMPEG2ADTSConfig(buffer, &sampleRate, &channelCount);
- LOGI("sampleRate = %d", sampleRate);
- LOGI("channelCount = %d", channelCount);
+ LOGV("sampleRate = %d", sampleRate);
+ LOGV("channelCount = %d", channelCount);
meta->setInt32(kKeySampleRate, sampleRate);
meta->setInt32(kKeyChannelCount, channelCount);
@@ -716,7 +727,7 @@ void ATSParser::Stream::onPayloadData(
meta->setData(kKeyESDS, 0, csd->data(), csd->size());
}
- LOGI("created source!");
+ LOGV("created source!");
mSource = new AnotherPacketSource(meta);
// fall through
@@ -915,7 +926,10 @@ void ATSParser::parseTS(ABitReader *br) {
unsigned adaptation_field_control = br->getBits(2);
LOGV("adaptation_field_control = %u", adaptation_field_control);
- MY_LOGV("continuity_counter = %u", br->getBits(4));
+ unsigned continuity_counter = br->getBits(4);
+ LOGV("continuity_counter = %u", continuity_counter);
+
+ // LOGI("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter);
if (adaptation_field_control == 2 || adaptation_field_control == 3) {
parseAdaptationField(br);
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 56ca375..2417305 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -32,6 +32,8 @@
namespace android {
+static const size_t kTSPacketSize = 188;
+
struct MPEG2TSSource : public MediaSource {
MPEG2TSSource(
const sp<MPEG2TSExtractor> &extractor,
@@ -126,27 +128,37 @@ sp<MetaData> MPEG2TSExtractor::getMetaData() {
void MPEG2TSExtractor::init() {
bool haveAudio = false;
bool haveVideo = false;
+ int numPacketsParsed = 0;
while (feedMore() == OK) {
ATSParser::SourceType type;
if (haveAudio && haveVideo) {
break;
}
- if (haveVideo) {
- type = ATSParser::MPEG2ADTS_AUDIO;
- } else {
- type = ATSParser::AVC_VIDEO;
+ if (!haveVideo) {
+ sp<AnotherPacketSource> impl =
+ (AnotherPacketSource *)mParser->getSource(
+ ATSParser::AVC_VIDEO).get();
+
+ if (impl != NULL) {
+ haveVideo = true;
+ mSourceImpls.push(impl);
+ }
}
- sp<AnotherPacketSource> impl =
- (AnotherPacketSource *)mParser->getSource(type).get();
- if (impl != NULL) {
- if (type == ATSParser::MPEG2ADTS_AUDIO) {
+ if (!haveAudio) {
+ sp<AnotherPacketSource> impl =
+ (AnotherPacketSource *)mParser->getSource(
+ ATSParser::MPEG2ADTS_AUDIO).get();
+
+ if (impl != NULL) {
haveAudio = true;
- } else {
- haveVideo = true;
+ mSourceImpls.push(impl);
}
- mSourceImpls.push(impl);
+ }
+
+ if (++numPacketsParsed > 1500) {
+ break;
}
}
@@ -156,8 +168,6 @@ void MPEG2TSExtractor::init() {
status_t MPEG2TSExtractor::feedMore() {
Mutex::Autolock autoLock(mLock);
- static const size_t kTSPacketSize = 188;
-
uint8_t packet[kTSPacketSize];
ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
@@ -176,23 +186,18 @@ status_t MPEG2TSExtractor::feedMore() {
bool SniffMPEG2TS(
const sp<DataSource> &source, String8 *mimeType, float *confidence,
sp<AMessage> *) {
-#if 0
- char header;
- if (source->readAt(0, &header, 1) != 1 || header != 0x47) {
- return false;
+ for (int i = 0; i < 5; ++i) {
+ char header;
+ if (source->readAt(kTSPacketSize * i, &header, 1) != 1
+ || header != 0x47) {
+ return false;
+ }
}
- *confidence = 0.05f;
+ *confidence = 0.1f;
mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
return true;
-#else
- // For now we're going to never identify this type of stream, since we'd
- // just base our decision on a single byte...
- // Instead you can instantiate an MPEG2TSExtractor by explicitly stating
- // its proper mime type in the call to MediaExtractor::Create(...).
- return false;
-#endif
}
} // namespace android
diff --git a/native/android/Android.mk b/native/android/Android.mk
index cc35a3a..44ec83f 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -12,6 +12,7 @@ LOCAL_SRC_FILES:= \
looper.cpp \
native_activity.cpp \
native_window.cpp \
+ obb.cpp \
sensor.cpp \
storage_manager.cpp
diff --git a/native/android/obb.cpp b/native/android/obb.cpp
new file mode 100644
index 0000000..e0cb1a6
--- /dev/null
+++ b/native/android/obb.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "NObb"
+
+#include <android/obb.h>
+
+#include <utils/Log.h>
+#include <utils/ObbFile.h>
+
+using namespace android;
+
+struct AObbInfo : public ObbFile {};
+
+AObbInfo* AObbScanner_getObbInfo(const char* filename) {
+ AObbInfo* obbFile = new AObbInfo();
+ if (obbFile == NULL || !obbFile->readFrom(filename)) {
+ delete obbFile;
+ return NULL;
+ }
+ obbFile->incStrong((void*)AObbScanner_getObbInfo);
+ return static_cast<AObbInfo*>(obbFile);
+}
+
+void AObbInfo_delete(AObbInfo* obbInfo) {
+ if (obbInfo != NULL) {
+ obbInfo->decStrong((void*)AObbScanner_getObbInfo);
+ }
+}
+
+const char* AObbInfo_getPackageName(AObbInfo* obbInfo) {
+ return obbInfo->getPackageName();
+}
+
+int32_t AObbInfo_getVersion(AObbInfo* obbInfo) {
+ return obbInfo->getVersion();
+}
+
+int32_t AObbInfo_getFlags(AObbInfo* obbInfo) {
+ return obbInfo->getFlags();
+}
diff --git a/native/android/storage_manager.cpp b/native/android/storage_manager.cpp
index 6dbe746..2f20641 100644
--- a/native/android/storage_manager.cpp
+++ b/native/android/storage_manager.cpp
@@ -38,20 +38,20 @@ public:
mStorageManager(mgr)
{}
- virtual void onObbResult(const android::String16& filename, const android::String16& state) {
- LOGD("Got obb result (%s, %s)\n", String8(filename).string(), String8(state).string());
- }
+ virtual void onObbResult(const android::String16& filename, const android::String16& state);
};
struct AStorageManager : public RefBase {
protected:
- void* mObbCallback;
+ AStorageManager_obbCallbackFunc mObbCallback;
+ void* mObbCallbackData;
sp<ObbActionListener> mObbActionListener;
sp<IMountService> mMountService;
public:
- AStorageManager() :
- mObbCallback(NULL)
+ AStorageManager()
+ : mObbCallback(NULL)
+ , mObbCallbackData(NULL)
{
}
@@ -73,8 +73,15 @@ public:
return true;
}
- void setObbCallback(void* cb) {
+ void setObbCallback(AStorageManager_obbCallbackFunc cb, void* data) {
mObbCallback = cb;
+ mObbCallbackData = data;
+ }
+
+ void fireCallback(const char* filename, const char* state) {
+ if (mObbCallback != NULL) {
+ mObbCallback(filename, state, mObbCallbackData);
+ }
}
void mountObb(const char* filename, const char* key) {
@@ -85,7 +92,7 @@ public:
void unmountObb(const char* filename, const bool force) {
String16 filename16(filename);
- mMountService->unmountObb(filename16, force);
+ mMountService->unmountObb(filename16, force, mObbActionListener);
}
int isObbMounted(const char* filename) {
@@ -104,6 +111,10 @@ public:
}
};
+void ObbActionListener::onObbResult(const android::String16& filename, const android::String16& state) {
+ mStorageManager->fireCallback(String8(filename).string(), String8(state).string());
+}
+
AStorageManager* AStorageManager_new() {
sp<AStorageManager> mgr = new AStorageManager();
@@ -120,8 +131,8 @@ void AStorageManager_delete(AStorageManager* mgr) {
}
}
-void AStorageManager_setObbCallback(AStorageManager* mgr, void* cb) {
- mgr->setObbCallback(cb);
+void AStorageManager_setObbCallback(AStorageManager* mgr, AStorageManager_obbCallbackFunc cb, void* data) {
+ mgr->setObbCallback(cb, data);
}
void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key) {
diff --git a/native/include/android/obb.h b/native/include/android/obb.h
new file mode 100644
index 0000000..65e9b2a
--- /dev/null
+++ b/native/include/android/obb.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_OBB_H
+#define ANDROID_OBB_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AObbInfo;
+typedef struct AObbInfo AObbInfo;
+
+enum {
+ AOBBINFO_OVERLAY = 0x0001,
+};
+
+/**
+ * Scan an OBB and get information about it.
+ */
+AObbInfo* AObbScanner_getObbInfo(const char* filename);
+
+/**
+ * Destroy the AObbInfo object. You must call this when finished with the object.
+ */
+void AObbInfo_delete(AObbInfo* obbInfo);
+
+/**
+ * Get the package name for the OBB.
+ */
+const char* AObbInfo_getPackageName(AObbInfo* obbInfo);
+
+/**
+ * Get the version of an OBB file.
+ */
+int32_t AObbInfo_getVersion(AObbInfo* obbInfo);
+
+/**
+ * Get the flags of an OBB file.
+ */
+int32_t AObbInfo_getFlags(AObbInfo* obbInfo);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_OBB_H
diff --git a/native/include/android/storage_manager.h b/native/include/android/storage_manager.h
index bbed8a4..6f925c1 100644
--- a/native/include/android/storage_manager.h
+++ b/native/include/android/storage_manager.h
@@ -37,17 +37,22 @@ AStorageManager* AStorageManager_new();
void AStorageManager_delete(AStorageManager* mgr);
/**
- * Callback to call when requested OBB is complete.
+ * Callback function for asynchronous calls made on OBB files.
*/
-void AStorageManager_setObbCallback(AStorageManager* mgr, void* cb);
+typedef void (*AStorageManager_obbCallbackFunc)(const char* filename, const char* state, void* data);
/**
- * Attempts to mount an OBB file.
+ * Callback to call when requested asynchronous OBB operation is complete.
+ */
+void AStorageManager_setObbCallback(AStorageManager* mgr, AStorageManager_obbCallbackFunc cb, void* data);
+
+/**
+ * Attempts to mount an OBB file. This is an asynchronous operation.
*/
void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key);
/**
- * Attempts to unmount an OBB file.
+ * Attempts to unmount an OBB file. This is an asynchronous operation.
*/
void AStorageManager_unmountObb(AStorageManager* mgr, const char* filename, const int force);
@@ -66,4 +71,4 @@ const char* AStorageManager_getMountedObbPath(AStorageManager* mgr, const char*
};
#endif
-#endif // ANDROID_PACKAGE_MANAGER_H
+#endif // ANDROID_STORAGE_MANAGER_H
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index f08bd3c..eb86277 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -156,7 +156,12 @@ public class DefaultContainerService extends IntentService {
}
public ObbInfo getObbInfo(String filename) {
- return ObbScanner.getObbInfo(filename);
+ try {
+ return ObbScanner.getObbInfo(filename);
+ } catch (IOException e) {
+ Log.d(TAG, "Couldn't get OBB info", e);
+ return null;
+ }
}
};
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
index 157491e..a0e59cf 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
index aea18ed..1626895 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
index 1a25a2c..3c2e2b9 100755..100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
index 2134d49..bb41db0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index a58e311..12d1d5c 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -71,6 +71,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="none"
+ android:overscrollMode="ifContentScrolls"
>
<com.android.systemui.statusbar.NotificationLinearLayout
android:id="@+id/notificationLinearLayout"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
index d89d093..31b78b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
@@ -99,7 +99,7 @@ public class CarrierLabel extends TextView {
}
if (showSpn && spn != null) {
if (something) {
- str.append(' ');
+ str.append('\n');
}
str.append(spn);
something = true;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8a732ed..97b8086 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -5332,6 +5332,15 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
}
}
+ // Release effect engine here so that it is done immediately. Otherwise it will be released
+ // by the destructor when the last strong reference on the this object is released which can
+ // happen after next process is called on this effect.
+ if (size == 0 && mEffectInterface != NULL) {
+ // release effect engine
+ EffectRelease(mEffectInterface);
+ mEffectInterface = NULL;
+ }
+
return size;
}
@@ -6145,21 +6154,36 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int
// Must be called with EffectChain::mLock locked
void AudioFlinger::EffectChain::process_l()
{
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread == 0) {
+ LOGW("process_l(): cannot promote mixer thread");
+ return;
+ }
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ bool isGlobalSession = (mSessionId == AudioSystem::SESSION_OUTPUT_MIX) ||
+ (mSessionId == AudioSystem::SESSION_OUTPUT_STAGE);
+ bool tracksOnSession = false;
+ if (!isGlobalSession) {
+ tracksOnSession =
+ playbackThread->hasAudioSession(mSessionId) & PlaybackThread::TRACK_SESSION;
+ }
+
size_t size = mEffects.size();
- for (size_t i = 0; i < size; i++) {
- mEffects[i]->process();
+ // do not process effect if no track is present in same audio session
+ if (isGlobalSession || tracksOnSession) {
+ for (size_t i = 0; i < size; i++) {
+ mEffects[i]->process();
+ }
}
for (size_t i = 0; i < size; i++) {
mEffects[i]->updateState();
}
// if no track is active, input buffer must be cleared here as the mixer process
// will not do it
- if (mSessionId > 0 && activeTracks() == 0) {
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- size_t numSamples = thread->frameCount() * thread->channelCount();
- memset(mInBuffer, 0, numSamples * sizeof(int16_t));
- }
+ if (tracksOnSession &&
+ activeTracks() == 0) {
+ size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount();
+ memset(mInBuffer, 0, numSamples * sizeof(int16_t));
}
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index cfba07a..265d613 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -46,6 +46,7 @@ import android.os.storage.IObbActionListener;
import android.os.storage.StorageResultCode;
import android.util.Slog;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -148,7 +149,7 @@ class MountService extends IMountService.Stub
* Mounted OBB tracking information. Used to track the current state of all
* OBBs.
*/
- final private Map<IObbActionListener, ObbState> mObbMounts = new HashMap<IObbActionListener, ObbState>();
+ final private Map<IObbActionListener, List<ObbState>> mObbMounts = new HashMap<IObbActionListener, List<ObbState>>();
final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
class ObbState implements IBinder.DeathRecipient {
@@ -160,13 +161,13 @@ class MountService extends IMountService.Stub
}
// OBB source filename
- String filename;
+ final String filename;
// Token of remote Binder caller
- IObbActionListener token;
+ final IObbActionListener token;
// Binder.callingUid()
- public int callerUid;
+ final public int callerUid;
// Whether this is mounted currently.
boolean mounted;
@@ -225,9 +226,9 @@ class MountService extends IMountService.Stub
private static final int MAX_UNMOUNT_RETRIES = 4;
class UnmountCallBack {
- String path;
+ final String path;
+ final boolean force;
int retries;
- boolean force;
UnmountCallBack(String path, boolean force) {
retries = 0;
@@ -242,7 +243,7 @@ class MountService extends IMountService.Stub
}
class UmsEnableCallBack extends UnmountCallBack {
- String method;
+ final String method;
UmsEnableCallBack(String path, String method, boolean force) {
super(path, force);
@@ -1450,11 +1451,6 @@ class MountService extends IMountService.Stub
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
}
- private boolean isCallerOwnerOfPackageOrSystem(String packageName) {
- final int callerUid = Binder.getCallingUid();
- return isUidOwnerOfPackageOrSystem(packageName, callerUid);
- }
-
private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
if (callerUid == android.os.Process.SYSTEM_UID) {
return true;
@@ -1506,6 +1502,12 @@ class MountService extends IMountService.Stub
waitForReady();
warnOnNotMounted();
+ if (filename == null) {
+ throw new IllegalArgumentException("filename cannot be null");
+ } else if (token == null) {
+ throw new IllegalArgumentException("token cannot be null");
+ }
+
final ObbState obbState;
synchronized (mObbMounts) {
@@ -1513,10 +1515,6 @@ class MountService extends IMountService.Stub
throw new IllegalArgumentException("OBB file is already mounted");
}
- if (mObbMounts.containsKey(token)) {
- throw new IllegalArgumentException("You may only have one OBB mounted at a time");
- }
-
final int callerUid = Binder.getCallingUid();
obbState = new ObbState(filename, token, callerUid);
addObbState(obbState);
@@ -1536,6 +1534,12 @@ class MountService extends IMountService.Stub
}
public void unmountObb(String filename, boolean force, IObbActionListener token) {
+ if (filename == null) {
+ throw new IllegalArgumentException("filename cannot be null");
+ } else if (token == null) {
+ throw new IllegalArgumentException("token cannot be null");
+ }
+
final ObbState obbState;
synchronized (mObbMounts) {
@@ -1543,6 +1547,12 @@ class MountService extends IMountService.Stub
throw new IllegalArgumentException("OBB is not mounted");
}
obbState = mObbPathToStateMap.get(filename);
+
+ if (Binder.getCallingUid() != obbState.callerUid) {
+ throw new SecurityException("caller UID does not match original mount caller UID");
+ } else if (!token.asBinder().equals(obbState.token.asBinder())) {
+ throw new SecurityException("caller does not match original mount caller");
+ }
}
UnmountObbAction action = new UnmountObbAction(obbState, force);
@@ -1554,14 +1564,25 @@ class MountService extends IMountService.Stub
private void addObbState(ObbState obbState) {
synchronized (mObbMounts) {
- mObbMounts.put(obbState.token, obbState);
+ List<ObbState> obbStates = mObbMounts.get(obbState.token);
+ if (obbStates == null) {
+ obbStates = new ArrayList<ObbState>();
+ mObbMounts.put(obbState.token, obbStates);
+ }
+ obbStates.add(obbState);
mObbPathToStateMap.put(obbState.filename, obbState);
}
}
private void removeObbState(ObbState obbState) {
synchronized (mObbMounts) {
- mObbMounts.remove(obbState.token);
+ final List<ObbState> obbStates = mObbMounts.get(obbState.token);
+ if (obbStates != null) {
+ obbStates.remove(obbState);
+ }
+ if (obbStates == null || obbStates.isEmpty()) {
+ mObbMounts.remove(obbState.token);
+ }
mObbPathToStateMap.remove(obbState.filename);
}
}
@@ -1737,7 +1758,7 @@ class MountService extends IMountService.Stub
}
}
- abstract void handleExecute() throws RemoteException;
+ abstract void handleExecute() throws RemoteException, IOException;
abstract void handleError();
}
@@ -1749,8 +1770,12 @@ class MountService extends IMountService.Stub
mKey = key;
}
- public void handleExecute() throws RemoteException {
- ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
+ public void handleExecute() throws RemoteException, IOException {
+ final ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
+ if (obbInfo == null) {
+ throw new IOException("Couldn't read OBB file: " + mObbState.filename);
+ }
+
if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
}
@@ -1773,15 +1798,17 @@ class MountService extends IMountService.Stub
if (rc == StorageResultCode.OperationSucceeded) {
try {
- mObbState.token.onObbResult(mObbState.filename, "mounted");
+ mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_MOUNTED);
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
} else {
- Slog.e(TAG, "Couldn't mount OBB file");
+ Slog.e(TAG, "Couldn't mount OBB file: " + rc);
// We didn't succeed, so remove this from the mount-set.
removeObbState(mObbState);
+
+ mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
}
}
@@ -1789,7 +1816,7 @@ class MountService extends IMountService.Stub
removeObbState(mObbState);
try {
- mObbState.token.onObbResult(mObbState.filename, "error");
+ mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
} catch (RemoteException e) {
Slog.e(TAG, "Couldn't send back OBB mount error for " + mObbState.filename);
}
@@ -1818,11 +1845,10 @@ class MountService extends IMountService.Stub
mForceUnmount = force;
}
- public void handleExecute() throws RemoteException {
- ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
-
- if (!isCallerOwnerOfPackageOrSystem(obbInfo.packageName)) {
- throw new IllegalArgumentException("Caller package does not match OBB file");
+ public void handleExecute() throws RemoteException, IOException {
+ final ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
+ if (obbInfo == null) {
+ throw new IOException("Couldn't read OBB file: " + mObbState.filename);
}
int rc = StorageResultCode.OperationSucceeded;
@@ -1843,13 +1869,13 @@ class MountService extends IMountService.Stub
removeObbState(mObbState);
try {
- mObbState.token.onObbResult(mObbState.filename, "unmounted");
+ mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_UNMOUNTED);
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
} else {
try {
- mObbState.token.onObbResult(mObbState.filename, "error");
+ mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
@@ -1860,7 +1886,7 @@ class MountService extends IMountService.Stub
removeObbState(mObbState);
try {
- mObbState.token.onObbResult(mObbState.filename, "error");
+ mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
} catch (RemoteException e) {
Slog.e(TAG, "Couldn't send back OBB unmount error for " + mObbState.filename);
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 5d32b74..71105f1 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -2105,6 +2105,7 @@ class PowerManagerService extends IPowerManager.Stub
}
public void userActivity(long time, boolean noChangeLights) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
userActivity(time, -1, noChangeLights, OTHER_EVENT, false);
}
@@ -2128,7 +2129,6 @@ class PowerManagerService extends IPowerManager.Stub
private void userActivity(long time, long timeoutOverride, boolean noChangeLights,
int eventType, boolean force) {
- //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
&& (eventType == CHEEK_EVENT || eventType == TOUCH_EVENT)) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a80ab1d..7f42429 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -19,6 +19,7 @@ package com.android.server;
import com.android.server.am.ActivityManagerService;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
+import com.trustedlogic.trustednfc.android.server.NfcService;
import dalvik.system.VMRuntime;
import dalvik.system.Zygote;
@@ -41,6 +42,7 @@ import android.server.BluetoothA2dpService;
import android.server.BluetoothService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
+import android.util.Log;
import android.util.Slog;
import android.accounts.AccountManagerService;
@@ -409,6 +411,20 @@ class ServerThread extends Thread {
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Recognition Service", e);
}
+
+ try {
+ Slog.i(TAG, "Nfc Service");
+ NfcService nfc;
+ try {
+ nfc = new NfcService(context);
+ } catch (UnsatisfiedLinkError e) { // gross hack to detect NFC
+ nfc = null;
+ Slog.w(TAG, "No NFC support");
+ }
+ ServiceManager.addService(Context.NFC_SERVICE, nfc);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting NFC Service", e);
+ }
try {
Slog.i(TAG, "DiskStats Service");
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index c047e10..3d95bf0 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -2209,7 +2209,7 @@ public class WifiService extends IWifiManager.Stub {
}
private boolean acquireWifiLockLocked(WifiLock wifiLock) {
- Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
+ if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
mLocks.addLock(wifiLock);
@@ -2279,7 +2279,7 @@ public class WifiService extends IWifiManager.Stub {
WifiLock wifiLock = mLocks.removeLock(lock);
- Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
+ if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
hadLock = (wifiLock != null);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 22cd8ff..34753e7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4218,29 +4218,75 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
- ProviderInfo pi, int uid, int modeFlags) {
+ ProviderInfo pi, Uri uri, int uid, int modeFlags) {
+ boolean readPerm = (modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0;
+ boolean writePerm = (modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid);
try {
- if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
- if ((pi.readPermission != null) &&
+ // Is the component private from the target uid?
+ final boolean prv = !pi.exported && pi.applicationInfo.uid != uid;
+
+ // Acceptable if the there is no read permission needed from the
+ // target or the target is holding the read permission.
+ if (!readPerm) {
+ if ((!prv && pi.readPermission == null) ||
(pm.checkUidPermission(pi.readPermission, uid)
- != PackageManager.PERMISSION_GRANTED)) {
- return false;
+ == PackageManager.PERMISSION_GRANTED)) {
+ readPerm = true;
}
}
- if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
- if ((pi.writePermission != null) &&
+
+ // Acceptable if the there is no write permission needed from the
+ // target or the target is holding the read permission.
+ if (!writePerm) {
+ if (!prv && (pi.writePermission == null) ||
(pm.checkUidPermission(pi.writePermission, uid)
- != PackageManager.PERMISSION_GRANTED)) {
- return false;
+ == PackageManager.PERMISSION_GRANTED)) {
+ writePerm = true;
}
}
- if (!pi.exported && pi.applicationInfo.uid != uid) {
- return false;
+
+ // Acceptable if there is a path permission matching the URI that
+ // the target holds the permission on.
+ PathPermission[] pps = pi.pathPermissions;
+ if (pps != null && (!readPerm || !writePerm)) {
+ final String path = uri.getPath();
+ int i = pps.length;
+ while (i > 0 && (!readPerm || !writePerm)) {
+ i--;
+ PathPermission pp = pps[i];
+ if (!readPerm) {
+ final String pprperm = pp.getReadPermission();
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
+ + pprperm + " for " + pp.getPath()
+ + ": match=" + pp.match(path)
+ + " check=" + pm.checkUidPermission(pprperm, uid));
+ if (pprperm != null && pp.match(path) &&
+ (pm.checkUidPermission(pprperm, uid)
+ == PackageManager.PERMISSION_GRANTED)) {
+ readPerm = true;
+ }
+ }
+ if (!writePerm) {
+ final String ppwperm = pp.getWritePermission();
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
+ + ppwperm + " for " + pp.getPath()
+ + ": match=" + pp.match(path)
+ + " check=" + pm.checkUidPermission(ppwperm, uid));
+ if (ppwperm != null && pp.match(path) &&
+ (pm.checkUidPermission(ppwperm, uid)
+ == PackageManager.PERMISSION_GRANTED)) {
+ writePerm = true;
+ }
+ }
+ }
}
- return true;
} catch (RemoteException e) {
return false;
}
+
+ return readPerm && writePerm;
}
private final boolean checkUriPermissionLocked(Uri uri, int uid,
@@ -4333,7 +4379,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// First... does the target actually need this permission?
- if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
+ if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags)) {
// No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Target " + targetPkg + " already has full permission to " + uri);
@@ -4367,7 +4413,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Third... does the caller itself have permission to access
// this uri?
- if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
+ if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
throw new SecurityException("Uid " + callingUid
+ " does not have permission to uri " + uri);
@@ -4535,7 +4581,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// Does the caller have this permission on the URI?
- if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
+ if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
// Right now, if you are not the original owner of the permission,
// you are not allowed to revoke it.
//if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
diff --git a/services/java/com/trustedlogic/trustednfc/android/server/NfcService.java b/services/java/com/trustedlogic/trustednfc/android/server/NfcService.java
new file mode 100644
index 0000000..431b798
--- /dev/null
+++ b/services/java/com/trustedlogic/trustednfc/android/server/NfcService.java
@@ -0,0 +1,2111 @@
+/*
+ * 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 com.trustedlogic.trustednfc.android.server;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.Set;
+
+import com.trustedlogic.trustednfc.android.ILlcpConnectionlessSocket;
+import com.trustedlogic.trustednfc.android.ILlcpServiceSocket;
+import com.trustedlogic.trustednfc.android.INfcManager;
+import com.trustedlogic.trustednfc.android.ILlcpSocket;
+import com.trustedlogic.trustednfc.android.INfcTag;
+import com.trustedlogic.trustednfc.android.IP2pInitiator;
+import com.trustedlogic.trustednfc.android.IP2pTarget;
+import com.trustedlogic.trustednfc.android.LlcpPacket;
+import com.trustedlogic.trustednfc.android.NdefMessage;
+import com.trustedlogic.trustednfc.android.NfcException;
+import com.trustedlogic.trustednfc.android.NfcManager;
+import com.trustedlogic.trustednfc.android.internal.NativeLlcpConnectionlessSocket;
+import com.trustedlogic.trustednfc.android.internal.NativeLlcpServiceSocket;
+import com.trustedlogic.trustednfc.android.internal.NativeLlcpSocket;
+import com.trustedlogic.trustednfc.android.internal.NativeNfcManager;
+import com.trustedlogic.trustednfc.android.internal.NativeNfcTag;
+import com.trustedlogic.trustednfc.android.internal.NativeP2pDevice;
+import com.trustedlogic.trustednfc.android.internal.ErrorCodes;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Log;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+public class NfcService extends INfcManager.Stub implements Runnable {
+
+ /**
+ * NFC Service tag
+ */
+ private static final String TAG = "NfcService";
+
+ /**
+ * NFC features disabled state
+ */
+ private static final short NFC_STATE_DISABLED = 0x00;
+
+ /**
+ * NFC features enabled state
+ */
+ private static final short NFC_STATE_ENABLED = 0x01;
+
+ /**
+ * NFC Discovery for Reader mode
+ */
+ private static final int DISCOVERY_MODE_READER = 0;
+
+ /**
+ * NFC Discovery for Card Emulation Mode
+ */
+ private static final int DISCOVERY_MODE_CARD_EMULATION = 2;
+
+ /**
+ * LLCP Service Socket type
+ */
+ private static final int LLCP_SERVICE_SOCKET_TYPE = 0;
+
+ /**
+ * LLCP Socket type
+ */
+ private static final int LLCP_SOCKET_TYPE = 1;
+
+ /**
+ * LLCP Connectionless socket type
+ */
+ private static final int LLCP_CONNECTIONLESS_SOCKET_TYPE = 2;
+
+ /**
+ * Maximun number of sockets managed
+ */
+ private static final int LLCP_SOCKET_NB_MAX = 5;
+
+ /**
+ * Default value for the Maximum Information Unit parameter
+ */
+ private static final int LLCP_LTO_DEFAULT_VALUE = 150;
+
+ /**
+ * Default value for the Maximum Information Unit parameter
+ */
+ private static final int LLCP_LTO_MAX_VALUE = 255;
+
+ /**
+ * Maximun value for the Receive Window
+ */
+ private static final int LLCP_RW_MAX_VALUE = 15;
+
+ /**
+ * Default value for the Maximum Information Unit parameter
+ */
+ private static final int LLCP_MIU_DEFAULT_VALUE = 128;
+
+ /**
+ * Default value for the Maximum Information Unit parameter
+ */
+ private static final int LLCP_MIU_MAX_VALUE = 2176;
+
+ /**
+ * Default value for the Well Known Service List parameter
+ */
+ private static final int LLCP_WKS_DEFAULT_VALUE = 1;
+
+ /**
+ * Max value for the Well Known Service List parameter
+ */
+ private static final int LLCP_WKS_MAX_VALUE = 15;
+
+ /**
+ * Default value for the Option parameter
+ */
+ private static final int LLCP_OPT_DEFAULT_VALUE = 0;
+
+ /**
+ * Max value for the Option parameter
+ */
+ private static final int LLCP_OPT_MAX_VALUE = 3;
+
+ /**
+ * LLCP Properties
+ */
+ private static final int PROPERTY_LLCP_LTO = 0;
+
+ private static final int PROPERTY_LLCP_MIU = 1;
+
+ private static final int PROPERTY_LLCP_WKS = 2;
+
+ private static final int PROPERTY_LLCP_OPT = 3;
+
+ private static final String PROPERTY_LLCP_LTO_VALUE = "llcp.lto";
+
+ private static final String PROPERTY_LLCP_MIU_VALUE = "llcp.miu";
+
+ private static final String PROPERTY_LLCP_WKS_VALUE = "llcp.wks";
+
+ private static final String PROPERTY_LLCP_OPT_VALUE = "llcp.opt";
+
+ /**
+ * NFC Reader Properties
+ */
+ private static final int PROPERTY_NFC_DISCOVERY_A = 4;
+
+ private static final int PROPERTY_NFC_DISCOVERY_B = 5;
+
+ private static final int PROPERTY_NFC_DISCOVERY_F = 6;
+
+ private static final int PROPERTY_NFC_DISCOVERY_15693 = 7;
+
+ private static final int PROPERTY_NFC_DISCOVERY_NFCIP = 8;
+
+ private static final String PROPERTY_NFC_DISCOVERY_A_VALUE = "discovery.iso14443A";
+
+ private static final String PROPERTY_NFC_DISCOVERY_B_VALUE = "discovery.iso14443B";
+
+ private static final String PROPERTY_NFC_DISCOVERY_F_VALUE = "discovery.felica";
+
+ private static final String PROPERTY_NFC_DISCOVERY_15693_VALUE = "discovery.iso15693";
+
+ private static final String PROPERTY_NFC_DISCOVERY_NFCIP_VALUE = "discovery.nfcip";
+
+ private Context mContext;
+
+ private HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
+
+ private HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>();
+
+ private LinkedList<RegisteredSocket> mRegisteredSocketList = new LinkedList<RegisteredSocket>();
+
+ private int mLlcpLinkState = NfcManager.LLCP_LINK_STATE_DEACTIVATED;
+
+ private int mGeneratedSocketHandle = 0;
+
+ private int mNbSocketCreated = 0;
+
+ private boolean mIsNfcEnabled = false;
+
+ private NfcHandler mNfcHandler;
+
+ private int mSelectedSeId = 0;
+
+ private int mTimeout = 0;
+
+ private int mNfcState;
+
+ private int mNfcSecureElementState;
+
+ private boolean mOpenPending = false;
+
+ private NativeNfcManager mManager;
+
+ private ILlcpSocket mLlcpSocket = new ILlcpSocket.Stub() {
+
+ public int close(int nativeHandle) throws RemoteException {
+ NativeLlcpSocket socket = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) {
+ isSuccess = socket.doClose();
+ if (isSuccess) {
+ /* Remove the socket closed from the hmap */
+ RemoveSocket(nativeHandle);
+ /* Update mNbSocketCreated */
+ mNbSocketCreated--;
+ return ErrorCodes.SUCCESS;
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ /* Remove the socket closed from the hmap */
+ RemoveSocket(nativeHandle);
+
+ /* Remove registered socket from the list */
+ RemoveRegisteredSocket(nativeHandle);
+
+ /* Update mNbSocketCreated */
+ mNbSocketCreated--;
+
+ return ErrorCodes.SUCCESS;
+ }
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ }
+
+ public int connect(int nativeHandle, int sap) throws RemoteException {
+ NativeLlcpSocket socket = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ isSuccess = socket.doConnect(sap, socket.getConnectTimeout());
+ if (isSuccess) {
+ return ErrorCodes.SUCCESS;
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+
+ }
+
+ public int connectByName(int nativeHandle, String sn) throws RemoteException {
+ NativeLlcpSocket socket = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ isSuccess = socket.doConnectBy(sn, socket.getConnectTimeout());
+ if (isSuccess) {
+ return ErrorCodes.SUCCESS;
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+
+ }
+
+ public int getConnectTimeout(int nativeHandle) throws RemoteException {
+ NativeLlcpSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ return socket.getConnectTimeout();
+ } else {
+ return 0;
+ }
+ }
+
+ public int getLocalSap(int nativeHandle) throws RemoteException {
+ NativeLlcpSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ return socket.getSap();
+ } else {
+ return 0;
+ }
+ }
+
+ public int getLocalSocketMiu(int nativeHandle) throws RemoteException {
+ NativeLlcpSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ return socket.getMiu();
+ } else {
+ return 0;
+ }
+ }
+
+ public int getLocalSocketRw(int nativeHandle) throws RemoteException {
+ NativeLlcpSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ return socket.getRw();
+ } else {
+ return 0;
+ }
+ }
+
+ public int getRemoteSocketMiu(int nativeHandle) throws RemoteException {
+ NativeLlcpSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ if (socket.doGetRemoteSocketMiu() != 0) {
+ return socket.doGetRemoteSocketMiu();
+ } else {
+ return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
+ }
+ } else {
+ return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
+ }
+ }
+
+ public int getRemoteSocketRw(int nativeHandle) throws RemoteException {
+ NativeLlcpSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ if (socket.doGetRemoteSocketRw() != 0) {
+ return socket.doGetRemoteSocketRw();
+ } else {
+ return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
+ }
+ } else {
+ return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
+ }
+ }
+
+ public int receive(int nativeHandle, byte[] receiveBuffer) throws RemoteException {
+ NativeLlcpSocket socket = null;
+ int receiveLength = 0;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ receiveLength = socket.doReceive(receiveBuffer);
+ if (receiveLength != 0) {
+ return receiveLength;
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ }
+
+ public int send(int nativeHandle, byte[] data) throws RemoteException {
+ NativeLlcpSocket socket = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ isSuccess = socket.doSend(data);
+ if (isSuccess) {
+ return ErrorCodes.SUCCESS;
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ }
+
+ public void setConnectTimeout(int nativeHandle, int timeout) throws RemoteException {
+ NativeLlcpSocket socket = null;
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ socket.setConnectTimeout(timeout);
+ }
+ }
+
+ };
+
+ private ILlcpServiceSocket mLlcpServerSocketService = new ILlcpServiceSocket.Stub() {
+
+ public int accept(int nativeHandle) throws RemoteException {
+ NativeLlcpServiceSocket socket = null;
+ NativeLlcpSocket clientSocket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) {
+ /* find the socket in the hmap */
+ socket = (NativeLlcpServiceSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ clientSocket = socket.doAccept(socket.getAcceptTimeout(), socket.getMiu(),
+ socket.getRw(), socket.getLinearBufferLength());
+ if (clientSocket != null) {
+ /* Add the socket into the socket map */
+ mSocketMap.put(clientSocket.getHandle(), clientSocket);
+ mNbSocketCreated++;
+ return clientSocket.getHandle();
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+
+ public void close(int nativeHandle) throws RemoteException {
+ NativeLlcpServiceSocket socket = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpServiceSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) {
+ isSuccess = socket.doClose();
+ if (isSuccess) {
+ /* Remove the socket closed from the hmap */
+ RemoveSocket(nativeHandle);
+ /* Update mNbSocketCreated */
+ mNbSocketCreated--;
+ }
+ } else {
+ /* Remove the socket closed from the hmap */
+ RemoveSocket(nativeHandle);
+
+ /* Remove registered socket from the list */
+ RemoveRegisteredSocket(nativeHandle);
+
+ /* Update mNbSocketCreated */
+ mNbSocketCreated--;
+ }
+ }
+ }
+
+ public int getAcceptTimeout(int nativeHandle) throws RemoteException {
+ NativeLlcpServiceSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpServiceSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ return socket.getAcceptTimeout();
+ } else {
+ return 0;
+ }
+ }
+
+ public void setAcceptTimeout(int nativeHandle, int timeout) throws RemoteException {
+ NativeLlcpServiceSocket socket = null;
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpServiceSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ socket.setAcceptTimeout(timeout);
+ }
+ }
+ };
+
+ private ILlcpConnectionlessSocket mLlcpConnectionlessSocketService = new ILlcpConnectionlessSocket.Stub() {
+
+ public void close(int nativeHandle) throws RemoteException {
+ NativeLlcpConnectionlessSocket socket = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) {
+ isSuccess = socket.doClose();
+ if (isSuccess) {
+ /* Remove the socket closed from the hmap */
+ RemoveSocket(nativeHandle);
+ /* Update mNbSocketCreated */
+ mNbSocketCreated--;
+ }
+ } else {
+ /* Remove the socket closed from the hmap */
+ RemoveSocket(nativeHandle);
+
+ /* Remove registered socket from the list */
+ RemoveRegisteredSocket(nativeHandle);
+
+ /* Update mNbSocketCreated */
+ mNbSocketCreated--;
+ }
+ }
+ }
+
+ public int getSap(int nativeHandle) throws RemoteException {
+ NativeLlcpConnectionlessSocket socket = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ return socket.getSap();
+ } else {
+ return 0;
+ }
+ }
+
+ public LlcpPacket receiveFrom(int nativeHandle) throws RemoteException {
+ NativeLlcpConnectionlessSocket socket = null;
+ LlcpPacket packet;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ packet = socket.doReceiveFrom(socket.getLinkMiu());
+ if (packet != null) {
+ return packet;
+ }
+ return null;
+ } else {
+ return null;
+ }
+ }
+
+ public int sendTo(int nativeHandle, LlcpPacket packet) throws RemoteException {
+ NativeLlcpConnectionlessSocket socket = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the socket in the hmap */
+ socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle);
+ if (socket != null) {
+ isSuccess = socket.doSendTo(packet.getRemoteSap(), packet.getDataBuffer());
+ if (isSuccess) {
+ return ErrorCodes.SUCCESS;
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_IO;
+ }
+ }
+ };
+
+ private INfcTag mNfcTagService = new INfcTag.Stub() {
+
+ public int close(int nativeHandle) throws RemoteException {
+ NativeNfcTag tag = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ if (tag.doDisconnect()) {
+ /* Remove the device from the hmap */
+ RemoveObject(nativeHandle);
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ mOpenPending = false;
+ return ErrorCodes.SUCCESS;
+ }
+
+ }
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ mOpenPending = false;
+ return ErrorCodes.ERROR_DISCONNECT;
+ }
+
+ public int connect(int nativeHandle) throws RemoteException {
+ NativeNfcTag tag = null;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ if (tag.doConnect())
+ return ErrorCodes.SUCCESS;
+ }
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ mOpenPending = false;
+ return ErrorCodes.ERROR_CONNECT;
+ }
+
+ public String getType(int nativeHandle) throws RemoteException {
+ NativeNfcTag tag = null;
+ String type;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ type = tag.getType();
+ return type;
+ }
+ return null;
+ }
+
+ public byte[] getUid(int nativeHandle) throws RemoteException {
+ NativeNfcTag tag = null;
+ byte[] uid;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ uid = tag.getUid();
+ return uid;
+ }
+ return null;
+ }
+
+ public boolean isNdef(int nativeHandle) throws RemoteException {
+ NativeNfcTag tag = null;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return isSuccess;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ isSuccess = tag.checkNDEF();
+ }
+ return isSuccess;
+ }
+
+ public byte[] transceive(int nativeHandle, byte[] data) throws RemoteException {
+ NativeNfcTag tag = null;
+ byte[] response;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ response = tag.doTransceive(data);
+ return response;
+ }
+ return null;
+ }
+
+ public NdefMessage read(int nativeHandle) throws RemoteException {
+ NativeNfcTag tag;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ byte[] buf = tag.doRead();
+ if (buf == null)
+ return null;
+
+ /* Create an NdefMessage */
+ try {
+ return new NdefMessage(buf);
+ } catch (NfcException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public boolean write(int nativeHandle, NdefMessage msg) throws RemoteException {
+ NativeNfcTag tag;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return isSuccess;
+ }
+
+ /* find the tag in the hmap */
+ tag = (NativeNfcTag) findObject(nativeHandle);
+ if (tag != null) {
+ isSuccess = tag.doWrite(msg.toByteArray());
+ }
+ return isSuccess;
+
+ }
+
+ };
+
+ private IP2pInitiator mP2pInitiatorService = new IP2pInitiator.Stub() {
+
+ public byte[] getGeneralBytes(int nativeHandle) throws RemoteException {
+ NativeP2pDevice device;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ byte[] buff = device.getGeneralBytes();
+ if (buff == null)
+ return null;
+ return buff;
+ }
+ return null;
+ }
+
+ public int getMode(int nativeHandle) throws RemoteException {
+ NativeP2pDevice device;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ return device.getMode();
+ }
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ public byte[] receive(int nativeHandle) throws RemoteException {
+ NativeP2pDevice device;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ byte[] buff = device.doReceive();
+ if (buff == null)
+ return null;
+ return buff;
+ }
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ mOpenPending = false;
+ return null;
+ }
+
+ public boolean send(int nativeHandle, byte[] data) throws RemoteException {
+ NativeP2pDevice device;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return isSuccess;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ isSuccess = device.doSend(data);
+ }
+ return isSuccess;
+ }
+ };
+
+ private IP2pTarget mP2pTargetService = new IP2pTarget.Stub() {
+
+ public int connect(int nativeHandle) throws RemoteException {
+ NativeP2pDevice device;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ if (device.doConnect()) {
+ return ErrorCodes.SUCCESS;
+ }
+ }
+ return ErrorCodes.ERROR_CONNECT;
+ }
+
+ public boolean disconnect(int nativeHandle) throws RemoteException {
+ NativeP2pDevice device;
+ boolean isSuccess = false;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return isSuccess;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ if (isSuccess = device.doDisconnect()) {
+ mOpenPending = false;
+ /* remove the device from the hmap */
+ RemoveObject(nativeHandle);
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ }
+ }
+ return isSuccess;
+
+ }
+
+ public byte[] getGeneralBytes(int nativeHandle) throws RemoteException {
+ NativeP2pDevice device;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ byte[] buff = device.getGeneralBytes();
+ if (buff == null)
+ return null;
+ return buff;
+ }
+ return null;
+ }
+
+ public int getMode(int nativeHandle) throws RemoteException {
+ NativeP2pDevice device;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ return device.getMode();
+ }
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ public byte[] transceive(int nativeHandle, byte[] data) throws RemoteException {
+ NativeP2pDevice device;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ /* find the device in the hmap */
+ device = (NativeP2pDevice) findObject(nativeHandle);
+ if (device != null) {
+ byte[] buff = device.doTransceive(data);
+ if (buff == null)
+ return null;
+ return buff;
+ }
+ return null;
+ }
+ };
+
+ private class NfcHandler extends Handler {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+
+ } catch (Exception e) {
+ // Log, don't crash!
+ Log.e(TAG, "Exception in NfcHandler.handleMessage:", e);
+ }
+ }
+
+ };
+
+ public NfcService(Context context) {
+ super();
+ mContext = context;
+ mManager = new NativeNfcManager(mContext);
+
+ mContext.registerReceiver(mNfcServiceReceiver, new IntentFilter(
+ NativeNfcManager.INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION));
+
+ mContext.registerReceiver(mNfcServiceReceiver, new IntentFilter(
+ NfcManager.LLCP_LINK_STATE_CHANGED_ACTION));
+
+ mContext.registerReceiver(mNfcServiceReceiver, new IntentFilter(
+ NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION));
+
+ Thread thread = new Thread(null, this, "NfcService");
+ thread.start();
+
+ mManager.initializeNativeStructure();
+
+ int nfcState = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_ON, 0);
+
+ if (nfcState == NFC_STATE_ENABLED) {
+ if (this._enable()) {
+ }
+ }
+
+ }
+
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ Looper.prepare();
+ mNfcHandler = new NfcHandler();
+ Looper.loop();
+ }
+
+ public void cancel() throws RemoteException {
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW,
+ "NFC_RAW permission required to cancel NFC opening");
+ if (mOpenPending) {
+ mOpenPending = false;
+ mManager.doCancel();
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ }
+ }
+
+ public int createLlcpConnectionlessSocket(int sap) throws RemoteException {
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_LLCP,
+ "NFC_LLCP permission required for LLCP operations with NFC service");
+
+ /* Check SAP is not already used */
+
+ /* Check nb socket created */
+ if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) {
+ /* Store the socket handle */
+ int sockeHandle = mGeneratedSocketHandle;
+
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) {
+ NativeLlcpConnectionlessSocket socket;
+
+ socket = mManager.doCreateLlcpConnectionlessSocket(sap);
+ if (socket != null) {
+ /* Update the number of socket created */
+ mNbSocketCreated++;
+
+ /* Add the socket into the socket map */
+ mSocketMap.put(sockeHandle, socket);
+
+ return sockeHandle;
+ } else {
+ /*
+ * socket creation error - update the socket handle
+ * generation
+ */
+ mGeneratedSocketHandle -= 1;
+
+ /* Get Error Status */
+ int errorStatus = mManager.doGetLastError();
+
+ switch (errorStatus) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ return ErrorCodes.ERROR_BUFFER_TO_SMALL;
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
+ default:
+ return ErrorCodes.ERROR_SOCKET_CREATION;
+ }
+ }
+ } else {
+ /* Check SAP is not already used */
+ if (!CheckSocketSap(sap)) {
+ return ErrorCodes.ERROR_SAP_USED;
+ }
+
+ NativeLlcpConnectionlessSocket socket = new NativeLlcpConnectionlessSocket(sap);
+
+ /* Add the socket into the socket map */
+ mSocketMap.put(sockeHandle, socket);
+
+ /* Update the number of socket created */
+ mNbSocketCreated++;
+
+ /* Create new registered socket */
+ RegisteredSocket registeredSocket = new RegisteredSocket(
+ LLCP_CONNECTIONLESS_SOCKET_TYPE, sockeHandle, sap);
+
+ /* Put this socket into a list of registered socket */
+ mRegisteredSocketList.add(registeredSocket);
+ }
+
+ /* update socket handle generation */
+ mGeneratedSocketHandle++;
+
+ return sockeHandle;
+
+ } else {
+ /* No socket available */
+ return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+
+ public int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength)
+ throws RemoteException {
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_LLCP,
+ "NFC_LLCP permission required for LLCP operations with NFC service");
+
+ if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) {
+ int sockeHandle = mGeneratedSocketHandle;
+
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) {
+ NativeLlcpServiceSocket socket;
+
+ socket = mManager.doCreateLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength);
+ if (socket != null) {
+ /* Update the number of socket created */
+ mNbSocketCreated++;
+ /* Add the socket into the socket map */
+ mSocketMap.put(sockeHandle, socket);
+ } else {
+ /* socket creation error - update the socket handle counter */
+ mGeneratedSocketHandle -= 1;
+
+ /* Get Error Status */
+ int errorStatus = mManager.doGetLastError();
+
+ switch (errorStatus) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ return ErrorCodes.ERROR_BUFFER_TO_SMALL;
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
+ default:
+ return ErrorCodes.ERROR_SOCKET_CREATION;
+ }
+ }
+ } else {
+
+ /* Check SAP is not already used */
+ if (!CheckSocketSap(sap)) {
+ return ErrorCodes.ERROR_SAP_USED;
+ }
+
+ /* Service Name */
+ if (!CheckSocketServiceName(sn)) {
+ return ErrorCodes.ERROR_SERVICE_NAME_USED;
+ }
+
+ /* Check socket options */
+ if (!CheckSocketOptions(miu, rw, linearBufferLength)) {
+ return ErrorCodes.ERROR_SOCKET_OPTIONS;
+ }
+
+ NativeLlcpServiceSocket socket = new NativeLlcpServiceSocket(sn);
+
+ /* Add the socket into the socket map */
+ mSocketMap.put(sockeHandle, socket);
+
+ /* Update the number of socket created */
+ mNbSocketCreated++;
+
+ /* Create new registered socket */
+ RegisteredSocket registeredSocket = new RegisteredSocket(LLCP_SERVICE_SOCKET_TYPE,
+ sockeHandle, sap, sn, miu, rw, linearBufferLength);
+
+ /* Put this socket into a list of registered socket */
+ mRegisteredSocketList.add(registeredSocket);
+ }
+
+ /* update socket handle generation */
+ mGeneratedSocketHandle += 1;
+
+ Log.d(TAG, "Llcp Service Socket Handle =" + sockeHandle);
+ return sockeHandle;
+ } else {
+ /* No socket available */
+ return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ public int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
+ throws RemoteException {
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_LLCP,
+ "NFC_LLCP permission required for LLCP operations with NFC service");
+
+ if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) {
+
+ int sockeHandle = mGeneratedSocketHandle;
+
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) {
+ NativeLlcpSocket socket;
+
+ socket = mManager.doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
+
+ if (socket != null) {
+ /* Update the number of socket created */
+ mNbSocketCreated++;
+ /* Add the socket into the socket map */
+ mSocketMap.put(sockeHandle, socket);
+ } else {
+ /*
+ * socket creation error - update the socket handle
+ * generation
+ */
+ mGeneratedSocketHandle -= 1;
+
+ /* Get Error Status */
+ int errorStatus = mManager.doGetLastError();
+
+ switch (errorStatus) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ return ErrorCodes.ERROR_BUFFER_TO_SMALL;
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
+ default:
+ return ErrorCodes.ERROR_SOCKET_CREATION;
+ }
+ }
+ } else {
+
+ /* Check SAP is not already used */
+ if (!CheckSocketSap(sap)) {
+ return ErrorCodes.ERROR_SAP_USED;
+ }
+
+ /* Check Socket options */
+ if (!CheckSocketOptions(miu, rw, linearBufferLength)) {
+ return ErrorCodes.ERROR_SOCKET_OPTIONS;
+ }
+
+ NativeLlcpSocket socket = new NativeLlcpSocket(sap, miu, rw);
+
+ /* Add the socket into the socket map */
+ mSocketMap.put(sockeHandle, socket);
+
+ /* Update the number of socket created */
+ mNbSocketCreated++;
+ /* Create new registered socket */
+ RegisteredSocket registeredSocket = new RegisteredSocket(LLCP_SOCKET_TYPE,
+ sockeHandle, sap, miu, rw, linearBufferLength);
+
+ /* Put this socket into a list of registered socket */
+ mRegisteredSocketList.add(registeredSocket);
+ }
+
+ /* update socket handle generation */
+ mGeneratedSocketHandle++;
+
+ return sockeHandle;
+ } else {
+ /* No socket available */
+ return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ public int deselectSecureElement() throws RemoteException {
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ if (mSelectedSeId == 0) {
+ return ErrorCodes.ERROR_NO_SE_CONNECTED;
+ }
+
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN,
+ "NFC_ADMIN permission required to deselect NFC Secure Element");
+
+ mManager.doDeselectSecureElement(mSelectedSeId);
+ mNfcSecureElementState = 0;
+ mSelectedSeId = 0;
+
+ /* Store that a secure element is deselected */
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.NFC_SECURE_ELEMENT_ON, 0);
+
+ /* Reset Secure Element ID */
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.NFC_SECURE_ELEMENT_ID, 0);
+
+
+ return ErrorCodes.SUCCESS;
+ }
+
+ public boolean disable() throws RemoteException {
+ boolean isSuccess = false;
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN,
+ "NFC_ADMIN permission required to disable NFC service");
+ if (isEnabled()) {
+ isSuccess = mManager.deinitialize();
+ if (isSuccess) {
+ mIsNfcEnabled = false;
+ }
+ }
+
+ updateNfcOnSetting();
+
+ return isSuccess;
+ }
+
+ public boolean enable() throws RemoteException {
+ boolean isSuccess = false;
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN,
+ "NFC_ADMIN permission required to enable NFC service");
+ if (!isEnabled()) {
+ reset();
+ isSuccess = _enable();
+ }
+ return isSuccess;
+ }
+
+ private boolean _enable() {
+ boolean isSuccess = mManager.initialize();
+ if (isSuccess) {
+ /* Check persistent properties */
+ checkProperties();
+
+ /* Check Secure Element setting */
+ mNfcSecureElementState = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_SECURE_ELEMENT_ON, 0);
+
+ if (mNfcSecureElementState == 1) {
+
+ int secureElementId = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_SECURE_ELEMENT_ID, 0);
+ int[] Se_list = mManager.doGetSecureElementList();
+ if (Se_list != null) {
+ for (int i = 0; i < Se_list.length; i++) {
+ if (Se_list[i] == secureElementId) {
+ mManager.doSelectSecureElement(Se_list[i]);
+ mSelectedSeId = Se_list[i];
+ break;
+ }
+ }
+ }
+ }
+
+ /* Start polling loop */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+
+ mIsNfcEnabled = true;
+ } else {
+ mIsNfcEnabled = false;
+ }
+
+ updateNfcOnSetting();
+
+ return isSuccess;
+ }
+
+ private void updateNfcOnSetting() {
+ int state;
+
+ if (mIsNfcEnabled) {
+ state = NFC_STATE_ENABLED;
+ } else {
+ state = NFC_STATE_DISABLED;
+ }
+
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_ON, state);
+ }
+
+ private void checkProperties() {
+ int value;
+
+ /* LLCP LTO */
+ value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_LTO,
+ LLCP_LTO_DEFAULT_VALUE);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_LTO, value);
+ mManager.doSetProperties(PROPERTY_LLCP_LTO, value);
+
+ /* LLCP MIU */
+ value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_MIU,
+ LLCP_MIU_DEFAULT_VALUE);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_MIU, value);
+ mManager.doSetProperties(PROPERTY_LLCP_MIU, value);
+
+ /* LLCP WKS */
+ value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_WKS,
+ LLCP_WKS_DEFAULT_VALUE);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_WKS, value);
+ mManager.doSetProperties(PROPERTY_LLCP_WKS, value);
+
+ /* LLCP OPT */
+ value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_OPT,
+ LLCP_OPT_DEFAULT_VALUE);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_OPT, value);
+ mManager.doSetProperties(PROPERTY_LLCP_OPT, value);
+
+ /* NFC READER A */
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_A, 1);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_A,
+ value);
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A, value);
+
+ /* NFC READER B */
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_B, 1);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_B,
+ value);
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B, value);
+
+ /* NFC READER F */
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_F, 1);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_F,
+ value);
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F, value);
+
+ /* NFC READER 15693 */
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_15693, 1);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_15693,
+ value);
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693, value);
+
+ /* NFC NFCIP */
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_NFCIP, 1);
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_NFCIP,
+ value);
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP, value);
+ }
+
+ public ILlcpConnectionlessSocket getLlcpConnectionlessInterface() throws RemoteException {
+ return mLlcpConnectionlessSocketService;
+ }
+
+ public ILlcpSocket getLlcpInterface() throws RemoteException {
+ return mLlcpSocket;
+ }
+
+ public ILlcpServiceSocket getLlcpServiceInterface() throws RemoteException {
+ return mLlcpServerSocketService;
+ }
+
+ public INfcTag getNfcTagInterface() throws RemoteException {
+ return mNfcTagService;
+ }
+
+ public int getOpenTimeout() throws RemoteException {
+ return mTimeout;
+ }
+
+ public IP2pInitiator getP2pInitiatorInterface() throws RemoteException {
+ return mP2pInitiatorService;
+ }
+
+ public IP2pTarget getP2pTargetInterface() throws RemoteException {
+ return mP2pTargetService;
+ }
+
+ public String getProperties(String param) throws RemoteException {
+ int value;
+
+ if (param == null) {
+ return "Wrong parameter";
+ }
+
+ if (param.equals(PROPERTY_LLCP_LTO_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_LLCP_LTO, 0);
+ } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_LLCP_MIU, 0);
+ } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_LLCP_WKS, 0);
+ } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_LLCP_OPT, 0);
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_A, 0);
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_B, 0);
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_F, 0);
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_NFCIP, 0);
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) {
+ value = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_15693, 0);
+ } else {
+ return "Unknown property";
+ }
+
+ if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)
+ || param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)
+ || param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)
+ || param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)
+ || param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) {
+ if (value == 0) {
+ return "false";
+ } else if (value == 1) {
+ return "true";
+ } else {
+ return "Unknown Value";
+ }
+ }else{
+ return "" + value;
+ }
+
+ }
+
+ public int[] getSecureElementList() throws RemoteException {
+ int[] list = null;
+ if (mIsNfcEnabled == true) {
+ list = mManager.doGetSecureElementList();
+ }
+ return list;
+ }
+
+ public int getSelectedSecureElement() throws RemoteException {
+ return mSelectedSeId;
+ }
+
+ public boolean isEnabled() throws RemoteException {
+ return mIsNfcEnabled;
+ }
+
+ public int openP2pConnection() throws RemoteException {
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW,
+ "NFC_RAW permission required to open NFC P2P connection");
+ if (!mOpenPending) {
+ NativeP2pDevice device;
+ mOpenPending = true;
+ device = mManager.doOpenP2pConnection(mTimeout);
+ if (device != null) {
+ /* add device to the Hmap */
+ mObjectMap.put(device.getHandle(), device);
+ return device.getHandle();
+ } else {
+ mOpenPending = false;
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_BUSY;
+ }
+
+ }
+
+ public int openTagConnection() throws RemoteException {
+ NativeNfcTag tag;
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW,
+ "NFC_RAW permission required to open NFC Tag connection");
+ if (!mOpenPending) {
+ mOpenPending = true;
+ tag = mManager.doOpenTagConnection(mTimeout);
+ if (tag != null) {
+ mObjectMap.put(tag.getHandle(), tag);
+ return tag.getHandle();
+ } else {
+ mOpenPending = false;
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ return ErrorCodes.ERROR_IO;
+ }
+ } else {
+ return ErrorCodes.ERROR_BUSY;
+ }
+ }
+
+ public int selectSecureElement(int seId) throws RemoteException {
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ if (mSelectedSeId == seId) {
+ return ErrorCodes.ERROR_SE_ALREADY_SELECTED;
+ }
+
+ if (mSelectedSeId != 0) {
+ return ErrorCodes.ERROR_SE_CONNECTED;
+ }
+
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN,
+ "NFC_ADMIN permission required to select NFC Secure Element");
+
+ mSelectedSeId = seId;
+ mManager.doSelectSecureElement(mSelectedSeId);
+
+ /* Store that a secure element is selected */
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.NFC_SECURE_ELEMENT_ON, 1);
+
+ /* Store the ID of the Secure Element Selected */
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.NFC_SECURE_ELEMENT_ID, mSelectedSeId);
+
+ mNfcSecureElementState = 1;
+
+ return ErrorCodes.SUCCESS;
+
+ }
+
+ public void setOpenTimeout(int timeout) throws RemoteException {
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW,
+ "NFC_RAW permission required to set NFC connection timeout");
+ mTimeout = timeout;
+ }
+
+ public int setProperties(String param, String value) throws RemoteException {
+ mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN,
+ "NFC_ADMIN permission required to set NFC Properties");
+
+ if (isEnabled()) {
+ return ErrorCodes.ERROR_NFC_ON;
+ }
+
+ int val;
+
+ /* Check params validity */
+ if (param == null || value == null) {
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ if (param.equals(PROPERTY_LLCP_LTO_VALUE)) {
+ val = Integer.parseInt(value);
+
+ /* Check params */
+ if (val > LLCP_LTO_MAX_VALUE)
+ return ErrorCodes.ERROR_INVALID_PARAM;
+
+ /* Store value */
+ Settings.System
+ .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_LTO, val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_LLCP_LTO, val);
+
+ } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) {
+ val = Integer.parseInt(value);
+
+ /* Check params */
+ if ((val < LLCP_MIU_DEFAULT_VALUE) || (val > LLCP_MIU_MAX_VALUE))
+ return ErrorCodes.ERROR_INVALID_PARAM;
+
+ /* Store value */
+ Settings.System
+ .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_MIU, val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_LLCP_MIU, val);
+
+ } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) {
+ val = Integer.parseInt(value);
+
+ /* Check params */
+ if (val > LLCP_WKS_MAX_VALUE)
+ return ErrorCodes.ERROR_INVALID_PARAM;
+
+ /* Store value */
+ Settings.System
+ .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_WKS, val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_LLCP_WKS, val);
+
+ } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) {
+ val = Integer.parseInt(value);
+
+ /* Check params */
+ if (val > LLCP_OPT_MAX_VALUE)
+ return ErrorCodes.ERROR_INVALID_PARAM;
+
+ /* Store value */
+ Settings.System
+ .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_OPT, val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_LLCP_OPT, val);
+
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) {
+
+ /* Check params */
+ if (value.equals("true")) {
+ val = 1;
+ } else if (value.equals("false")) {
+ val = 0;
+ } else {
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+ /* Store value */
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_A,
+ val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A, val);
+
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) {
+
+ /* Check params */
+ if (value.equals("true")) {
+ val = 1;
+ } else if (value.equals("false")) {
+ val = 0;
+ } else {
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ /* Store value */
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_B,
+ val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B, val);
+
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) {
+
+ /* Check params */
+ if (value.equals("true")) {
+ val = 1;
+ } else if (value.equals("false")) {
+ val = 0;
+ } else {
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ /* Store value */
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_F,
+ val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F, val);
+
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) {
+
+ /* Check params */
+ if (value.equals("true")) {
+ val = 1;
+ } else if (value.equals("false")) {
+ val = 0;
+ } else {
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ /* Store value */
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_15693, val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693, val);
+
+ } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) {
+
+ /* Check params */
+ if (value.equals("true")) {
+ val = 1;
+ } else if (value.equals("false")) {
+ val = 0;
+ } else {
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ /* Store value */
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.NFC_DISCOVERY_NFCIP, val);
+
+ /* Update JNI */
+ mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP, val);
+ } else {
+ return ErrorCodes.ERROR_INVALID_PARAM;
+ }
+
+ return ErrorCodes.SUCCESS;
+ }
+
+ // Reset all internals
+ private void reset() {
+
+ // Clear tables
+ mObjectMap.clear();
+ mSocketMap.clear();
+ mRegisteredSocketList.clear();
+
+ // Reset variables
+ mLlcpLinkState = NfcManager.LLCP_LINK_STATE_DEACTIVATED;
+ mNbSocketCreated = 0;
+ mIsNfcEnabled = false;
+ mSelectedSeId = 0;
+ mTimeout = 0;
+ mNfcState = NFC_STATE_DISABLED;
+ mOpenPending = false;
+ }
+
+ private Object findObject(int key) {
+ Object device = null;
+
+ device = mObjectMap.get(key);
+
+ return device;
+ }
+
+ private void RemoveObject(int key) {
+ mObjectMap.remove(key);
+ }
+
+ private Object findSocket(int key) {
+ Object socket = null;
+
+ socket = mSocketMap.get(key);
+
+ return socket;
+ }
+
+ private void RemoveSocket(int key) {
+ mSocketMap.remove(key);
+ }
+
+ private boolean CheckSocketSap(int sap) {
+ /* List of sockets registered */
+ ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator();
+
+ while (it.hasNext()) {
+ RegisteredSocket registeredSocket = it.next();
+
+ if (sap == registeredSocket.mSap) {
+ /* SAP already used */
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean CheckSocketOptions(int miu, int rw, int linearBufferlength) {
+
+ if (rw > LLCP_RW_MAX_VALUE || miu < LLCP_MIU_DEFAULT_VALUE || linearBufferlength < miu) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean CheckSocketServiceName(String sn) {
+
+ /* List of sockets registered */
+ ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator();
+
+ while (it.hasNext()) {
+ RegisteredSocket registeredSocket = it.next();
+
+ if (sn.equals(registeredSocket.mServiceName)) {
+ /* Service Name already used */
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void RemoveRegisteredSocket(int nativeHandle) {
+ /* check if sockets are registered */
+ ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator();
+
+ while (it.hasNext()) {
+ RegisteredSocket registeredSocket = it.next();
+ if (registeredSocket.mHandle == nativeHandle) {
+ /* remove the registered socket from the list */
+ it.remove();
+ Log.d(TAG, "socket removed");
+ }
+ }
+ }
+
+ /*
+ * RegisteredSocket class to store the creation request of socket until the
+ * LLCP link in not activated
+ */
+ private class RegisteredSocket {
+ private int mType;
+
+ private int mHandle;
+
+ private int mSap;
+
+ private int mMiu;
+
+ private int mRw;
+
+ private String mServiceName;
+
+ private int mlinearBufferLength;
+
+ RegisteredSocket(int type, int handle, int sap, String sn, int miu, int rw,
+ int linearBufferLength) {
+ mType = type;
+ mHandle = handle;
+ mSap = sap;
+ mServiceName = sn;
+ mRw = rw;
+ mMiu = miu;
+ mlinearBufferLength = linearBufferLength;
+ }
+
+ RegisteredSocket(int type, int handle, int sap, int miu, int rw, int linearBufferLength) {
+ mType = type;
+ mHandle = handle;
+ mSap = sap;
+ mRw = rw;
+ mMiu = miu;
+ mlinearBufferLength = linearBufferLength;
+ }
+
+ RegisteredSocket(int type, int handle, int sap) {
+ mType = type;
+ mHandle = handle;
+ mSap = sap;
+ }
+ }
+
+ private BroadcastReceiver mNfcServiceReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "Internal NFC Intent received");
+
+ /* LLCP Link deactivation */
+ if (intent.getAction().equals(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION)) {
+ mLlcpLinkState = intent.getIntExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA,
+ NfcManager.LLCP_LINK_STATE_DEACTIVATED);
+
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_DEACTIVATED) {
+ /* restart polling loop */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+ }
+
+ }
+ /* LLCP Link activation */
+ else if (intent.getAction().equals(
+ NativeNfcManager.INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION)) {
+
+ mLlcpLinkState = intent.getIntExtra(
+ NativeNfcManager.INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA,
+ NfcManager.LLCP_LINK_STATE_DEACTIVATED);
+
+ if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) {
+ /* check if sockets are registered */
+ ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator();
+
+ Log.d(TAG, "Nb socket resgistered = " + mRegisteredSocketList.size());
+
+ while (it.hasNext()) {
+ RegisteredSocket registeredSocket = it.next();
+
+ switch (registeredSocket.mType) {
+ case LLCP_SERVICE_SOCKET_TYPE:
+ Log.d(TAG, "Registered Llcp Service Socket");
+ NativeLlcpServiceSocket serviceSocket;
+
+ serviceSocket = mManager.doCreateLlcpServiceSocket(
+ registeredSocket.mSap, registeredSocket.mServiceName,
+ registeredSocket.mMiu, registeredSocket.mRw,
+ registeredSocket.mlinearBufferLength);
+
+ if (serviceSocket != null) {
+ /* Add the socket into the socket map */
+ mSocketMap.put(registeredSocket.mHandle, serviceSocket);
+ } else {
+ /*
+ * socket creation error - update the socket
+ * handle counter
+ */
+ mGeneratedSocketHandle -= 1;
+ }
+ break;
+
+ case LLCP_SOCKET_TYPE:
+ Log.d(TAG, "Registered Llcp Socket");
+ NativeLlcpSocket clientSocket;
+ clientSocket = mManager.doCreateLlcpSocket(registeredSocket.mSap,
+ registeredSocket.mMiu, registeredSocket.mRw,
+ registeredSocket.mlinearBufferLength);
+ if (clientSocket != null) {
+ /* Add the socket into the socket map */
+ mSocketMap.put(registeredSocket.mHandle, clientSocket);
+ } else {
+ /*
+ * socket creation error - update the socket
+ * handle counter
+ */
+ mGeneratedSocketHandle -= 1;
+ }
+ break;
+
+ case LLCP_CONNECTIONLESS_SOCKET_TYPE:
+ Log.d(TAG, "Registered Llcp Connectionless Socket");
+ NativeLlcpConnectionlessSocket connectionlessSocket;
+ connectionlessSocket = mManager
+ .doCreateLlcpConnectionlessSocket(registeredSocket.mSap);
+ if (connectionlessSocket != null) {
+ /* Add the socket into the socket map */
+ mSocketMap.put(registeredSocket.mHandle, connectionlessSocket);
+ } else {
+ /*
+ * socket creation error - update the socket
+ * handle counter
+ */
+ mGeneratedSocketHandle -= 1;
+ }
+ break;
+
+ }
+ }
+
+ /* Remove all registered socket from the list */
+ mRegisteredSocketList.clear();
+
+ /* Broadcast Intent Link LLCP activated */
+ Intent LlcpLinkIntent = new Intent();
+ LlcpLinkIntent.setAction(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION);
+
+ LlcpLinkIntent.putExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA,
+ NfcManager.LLCP_LINK_STATE_ACTIVATED);
+
+ Log.d(TAG, "Broadcasting LLCP activation");
+ mContext.sendOrderedBroadcast(LlcpLinkIntent,
+ android.Manifest.permission.NFC_LLCP);
+ }
+ }
+ /* Target Deactivated */
+ else if (intent.getAction().equals(
+ NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
+ if(mOpenPending != false){
+ mOpenPending = false;
+ }
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+
+ }
+ }
+ };
+}
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index 3b6de6f..0d983b5 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -42,6 +42,7 @@ public abstract class Connection {
NUMBER_UNREACHABLE, /* cannot reach the peer */
INVALID_CREDENTIALS, /* invalid credentials */
OUT_OF_NETWORK, /* calling from out of network is not allowed */
+ SERVER_ERROR, /* server error */
TIMED_OUT, /* client timed out */
LOST_SIGNAL,
LIMIT_EXCEEDED, /* eg GSM ACM limit exceeded */
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 999da9f..bceceda 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -441,18 +441,23 @@ public class SipPhone extends SipPhoneBase {
@Override
public void hangup() throws CallStateException {
synchronized (SipPhone.class) {
- Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this
- + " on phone " + getPhone());
- CallStateException excp = null;
- for (Connection c : connections) {
- try {
- c.hangup();
- } catch (CallStateException e) {
- excp = e;
+ if (state.isAlive()) {
+ Log.d(LOG_TAG, "hang up call: " + getState() + ": " + this
+ + " on phone " + getPhone());
+ CallStateException excp = null;
+ for (Connection c : connections) {
+ try {
+ c.hangup();
+ } catch (CallStateException e) {
+ excp = e;
+ }
}
+ if (excp != null) throw excp;
+ setState(State.DISCONNECTING);
+ } else {
+ Log.d(LOG_TAG, "hang up dead call: " + getState() + ": "
+ + this + " on phone " + getPhone());
}
- if (excp != null) throw excp;
- setState(State.DISCONNECTING);
}
}
@@ -637,14 +642,14 @@ public class SipPhone extends SipPhoneBase {
@Override
public void onCallEstablished(SipAudioCall call) {
- call.startAudio();
onChanged(call);
+ if (mState == Call.State.ACTIVE) call.startAudio();
}
@Override
public void onCallHeld(SipAudioCall call) {
- call.startAudio();
onChanged(call);
+ if (mState == Call.State.HOLDING) call.startAudio();
}
@Override
@@ -784,11 +789,13 @@ public class SipPhone extends SipPhoneBase {
public void hangup() throws CallStateException {
synchronized (SipPhone.class) {
Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
- + ": on phone " + getPhone().getPhoneName());
+ + mState + ": on phone " + getPhone().getPhoneName());
try {
- if (mSipAudioCall != null) mSipAudioCall.endCall();
- setState(Call.State.DISCONNECTING);
- setDisconnectCause(DisconnectCause.LOCAL);
+ if (mState.isAlive()) {
+ if (mSipAudioCall != null) mSipAudioCall.endCall();
+ setState(Call.State.DISCONNECTING);
+ setDisconnectCause(DisconnectCause.LOCAL);
+ }
} catch (SipException e) {
throw new CallStateException("hangup(): " + e);
}
@@ -876,8 +883,10 @@ public class SipPhone extends SipPhoneBase {
case SipErrorCode.CROSS_DOMAIN_AUTHENTICATION:
onError(Connection.DisconnectCause.OUT_OF_NETWORK);
break;
- case SipErrorCode.SOCKET_ERROR:
case SipErrorCode.SERVER_ERROR:
+ onError(Connection.DisconnectCause.SERVER_ERROR);
+ break;
+ case SipErrorCode.SOCKET_ERROR:
case SipErrorCode.CLIENT_ERROR:
default:
Log.w(LOG_TAG, "error: " + SipErrorCode.toString(errorCode)
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 135a633..b27ce0e 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -25,15 +25,11 @@ include $(CLEAR_VARS)
# We need to process the framework classes.jar file, but we can't
# depend directly on it (private vars won't be inherited correctly).
# So, we depend on framework's BUILT file.
-built_framework_dep := \
- $(call intermediates-dir-for,JAVA_LIBRARIES,framework)/javalib.jar
-built_framework_classes := \
- $(call intermediates-dir-for,JAVA_LIBRARIES,framework)/classes.jar
+built_framework_dep := $(call java-lib-deps,framework)
+built_framework_classes := $(call java-lib-files,framework)
-built_core_dep := \
- $(call intermediates-dir-for,JAVA_LIBRARIES,core)/javalib.jar
-built_core_classes := \
- $(call intermediates-dir-for,JAVA_LIBRARIES,core)/classes.jar
+built_core_dep := $(call java-lib-deps,core)
+built_core_classes := $(call java-lib-files,core)
built_layoutlib_create_jar := $(call intermediates-dir-for, \
JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
diff --git a/voip/java/android/net/rtp/AudioCodec.java b/voip/java/android/net/rtp/AudioCodec.java
index 4851a46..f171806 100644
--- a/voip/java/android/net/rtp/AudioCodec.java
+++ b/voip/java/android/net/rtp/AudioCodec.java
@@ -81,7 +81,7 @@ public class AudioCodec {
public static final AudioCodec AMR = new AudioCodec(97, "AMR/8000", null);
// TODO: add rest of the codecs when the native part is done.
- private static final AudioCodec[] sCodecs = {PCMU, PCMA};
+ private static final AudioCodec[] sCodecs = {GSM_EFR, GSM, PCMU, PCMA};
private AudioCodec(int type, String rtpmap, String fmtp) {
this.type = type;
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 91677a2..4321d7b 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -28,7 +28,6 @@ import android.net.sip.ISipSessionListener;
import android.net.sip.SipErrorCode;
import android.net.sip.SipProfile;
import android.net.sip.SipSession;
-import android.net.sip.SipSessionAdapter;
import android.text.TextUtils;
import android.util.Log;
@@ -82,7 +81,6 @@ class SipSessionGroup implements SipListener {
private static final boolean DEBUG = true;
private static final boolean DEBUG_PING = DEBUG && false;
private static final String ANONYMOUS = "anonymous";
- private static final String SERVER_ERROR_PREFIX = "Response: ";
private static final int EXPIRY_TIME = 3600; // in seconds
private static final int CANCEL_CALL_TIMER = 3; // in seconds
@@ -960,6 +958,11 @@ class SipSessionGroup implements SipListener {
int statusCode = response.getStatusCode();
switch (statusCode) {
case Response.RINGING:
+ case Response.CALL_IS_BEING_FORWARDED:
+ case Response.QUEUED:
+ case Response.SESSION_PROGRESS:
+ // feedback any provisional responses (except TRYING) as
+ // ring back for better UX
if (mState == SipSession.State.OUTGOING_CALL) {
mState = SipSession.State.OUTGOING_CALL_RING_BACK;
mProxy.onRingingBack(this);
@@ -1099,8 +1102,8 @@ class SipSessionGroup implements SipListener {
}
private String createErrorMessage(Response response) {
- return String.format(SERVER_ERROR_PREFIX + "%s (%d)",
- response.getReasonPhrase(), response.getStatusCode());
+ return String.format("%s (%d)", response.getReasonPhrase(),
+ response.getStatusCode());
}
private void establishCall() {
@@ -1204,8 +1207,6 @@ class SipSessionGroup implements SipListener {
return SipErrorCode.INVALID_REMOTE_URI;
} else if (exception instanceof IOException) {
return SipErrorCode.SOCKET_ERROR;
- } else if (message.startsWith(SERVER_ERROR_PREFIX)) {
- return SipErrorCode.SERVER_ERROR;
} else {
return SipErrorCode.CLIENT_ERROR;
}
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
new file mode 100644
index 0000000..9a2227d
--- /dev/null
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyrightm (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.
+ */
+
+#include "AudioCodec.h"
+
+#include "gsmamr_dec.h"
+#include "gsmamr_enc.h"
+
+namespace {
+
+class GsmEfrCodec : public AudioCodec
+{
+public:
+ GsmEfrCodec() {
+ if (AMREncodeInit(&mEncoder, &mSidSync, false)) {
+ mEncoder = NULL;
+ }
+ if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) {
+ mDecoder = NULL;
+ }
+ }
+
+ ~GsmEfrCodec() {
+ if (mEncoder) {
+ AMREncodeExit(&mEncoder, &mSidSync);
+ }
+ if (mDecoder) {
+ GSMDecodeFrameExit(&mDecoder);
+ }
+ }
+
+ int set(int sampleRate, const char *fmtp) {
+ return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1;
+ }
+
+ int encode(void *payload, int16_t *samples);
+ int decode(int16_t *samples, void *payload, int length);
+
+private:
+ void *mEncoder;
+ void *mSidSync;
+ void *mDecoder;
+};
+
+int GsmEfrCodec::encode(void *payload, int16_t *samples)
+{
+ unsigned char *bytes = (unsigned char *)payload;
+ Frame_Type_3GPP type;
+
+ int length = AMREncode(mEncoder, mSidSync, MR122,
+ samples, bytes, &type, AMR_TX_WMF);
+
+ if (type == AMR_122 && length == 32) {
+ bytes[0] = 0xC0 | (bytes[1] >> 4);
+ for (int i = 1; i < 31; ++i) {
+ bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
+ }
+ return 31;
+ }
+ return -1;
+}
+
+int GsmEfrCodec::decode(int16_t *samples, void *payload, int length)
+{
+ unsigned char *bytes = (unsigned char *)payload;
+ if (length == 31 && (bytes[0] >> 4) == 0x0C) {
+ for (int i = 0; i < 30; ++i) {
+ bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
+ }
+ bytes[30] <<= 4;
+
+ if (AMRDecode(mDecoder, AMR_122, bytes, samples, MIME_IETF) == 31) {
+ return 160;
+ }
+ }
+ return -1;
+}
+
+} // namespace
+
+AudioCodec *newGsmEfrCodec()
+{
+ return new GsmEfrCodec;
+}
diff --git a/voip/jni/rtp/Android.mk b/voip/jni/rtp/Android.mk
index a364355..5909c0d 100644
--- a/voip/jni/rtp/Android.mk
+++ b/voip/jni/rtp/Android.mk
@@ -26,16 +26,29 @@ LOCAL_SRC_FILES := \
util.cpp \
rtp_jni.cpp
+LOCAL_SRC_FILES += \
+ AmrCodec.cpp \
+ G711Codec.cpp \
+ GsmCodec.cpp
+
LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
- libmedia
+ libmedia \
+ libstagefright
-LOCAL_STATIC_LIBRARIES :=
+LOCAL_STATIC_LIBRARIES := libgsm
LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+ $(JNI_H_INCLUDE) \
+ external/libgsm/inc \
+ frameworks/base/media/libstagefright/codecs/amrnb/common/include \
+ frameworks/base/media/libstagefright/codecs/amrnb/common/ \
+ frameworks/base/media/libstagefright/codecs/amrnb/enc/include \
+ frameworks/base/media/libstagefright/codecs/amrnb/enc/src \
+ frameworks/base/media/libstagefright/codecs/amrnb/dec/include \
+ frameworks/base/media/libstagefright/codecs/amrnb/dec/src
LOCAL_CFLAGS += -fvisibility=hidden
diff --git a/voip/jni/rtp/AudioCodec.cpp b/voip/jni/rtp/AudioCodec.cpp
index 4d8d36c..afc193c 100644
--- a/voip/jni/rtp/AudioCodec.cpp
+++ b/voip/jni/rtp/AudioCodec.cpp
@@ -18,124 +18,10 @@
#include "AudioCodec.h"
-namespace {
-
-int8_t gExponents[128] = {
- 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-};
-
-//------------------------------------------------------------------------------
-
-class UlawCodec : public AudioCodec
-{
-public:
- int set(int sampleRate, const char *fmtp) {
- mSampleCount = sampleRate / 50;
- return mSampleCount;
- }
- int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
-private:
- int mSampleCount;
-};
-
-int UlawCodec::encode(void *payload, int16_t *samples)
-{
- int8_t *ulaws = (int8_t *)payload;
- for (int i = 0; i < mSampleCount; ++i) {
- int sample = samples[i];
- int sign = (sample >> 8) & 0x80;
- if (sample < 0) {
- sample = -sample;
- }
- sample += 132;
- if (sample > 32767) {
- sample = 32767;
- }
- int exponent = gExponents[sample >> 8];
- int mantissa = (sample >> (exponent + 3)) & 0x0F;
- ulaws[i] = ~(sign | (exponent << 4) | mantissa);
- }
- return mSampleCount;
-}
-
-int UlawCodec::decode(int16_t *samples, void *payload, int length)
-{
- int8_t *ulaws = (int8_t *)payload;
- for (int i = 0; i < length; ++i) {
- int ulaw = ~ulaws[i];
- int exponent = (ulaw >> 4) & 0x07;
- int mantissa = ulaw & 0x0F;
- int sample = (((mantissa << 3) + 132) << exponent) - 132;
- samples[i] = (ulaw < 0 ? -sample : sample);
- }
- return length;
-}
-
-AudioCodec *newUlawCodec()
-{
- return new UlawCodec;
-}
-
-//------------------------------------------------------------------------------
-
-class AlawCodec : public AudioCodec
-{
-public:
- int set(int sampleRate, const char *fmtp) {
- mSampleCount = sampleRate / 50;
- return mSampleCount;
- }
- int encode(void *payload, int16_t *samples);
- int decode(int16_t *samples, void *payload, int length);
-private:
- int mSampleCount;
-};
-
-int AlawCodec::encode(void *payload, int16_t *samples)
-{
- int8_t *alaws = (int8_t *)payload;
- for (int i = 0; i < mSampleCount; ++i) {
- int sample = samples[i];
- int sign = (sample >> 8) & 0x80;
- if (sample < 0) {
- sample = -sample;
- }
- if (sample > 32767) {
- sample = 32767;
- }
- int exponent = gExponents[sample >> 8];
- int mantissa = (sample >> (exponent == 0 ? 4 : exponent + 3)) & 0x0F;
- alaws[i] = (sign | (exponent << 4) | mantissa) ^ 0xD5;
- }
- return mSampleCount;
-}
-
-int AlawCodec::decode(int16_t *samples, void *payload, int length)
-{
- int8_t *alaws = (int8_t *)payload;
- for (int i = 0; i < length; ++i) {
- int alaw = alaws[i] ^ 0x55;
- int exponent = (alaw >> 4) & 0x07;
- int mantissa = alaw & 0x0F;
- int sample = (exponent == 0 ? (mantissa << 4) + 8 :
- ((mantissa << 3) + 132) << exponent);
- samples[i] = (alaw < 0 ? sample : -sample);
- }
- return length;
-}
-
-AudioCodec *newAlawCodec()
-{
- return new AlawCodec;
-}
+extern AudioCodec *newAlawCodec();
+extern AudioCodec *newUlawCodec();
+extern AudioCodec *newGsmCodec();
+extern AudioCodec *newGsmEfrCodec();
struct AudioCodecType {
const char *name;
@@ -143,11 +29,11 @@ struct AudioCodecType {
} gAudioCodecTypes[] = {
{"PCMA", newAlawCodec},
{"PCMU", newUlawCodec},
+ {"GSM", newGsmCodec},
+ {"GSM-EFR", newGsmEfrCodec},
{NULL, NULL},
};
-} // namespace
-
AudioCodec *newAudioCodec(const char *codecName)
{
AudioCodecType *type = gAudioCodecTypes;
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 81d4dfc..f09edb6 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -86,8 +86,6 @@ public:
void decode(int tick);
private:
- bool isNatAddress(struct sockaddr_storage *addr);
-
enum {
NORMAL = 0,
SEND_ONLY = 1,
@@ -101,6 +99,7 @@ private:
AudioCodec *mCodec;
uint32_t mCodecMagic;
uint32_t mDtmfMagic;
+ bool mFixRemote;
int mTick;
int mSampleRate;
@@ -181,6 +180,20 @@ bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
if (codec) {
mRemote = *remote;
mCodec = codec;
+
+ // Here we should never get an private address, but some buggy proxy
+ // servers do give us one. To solve this, we replace the address when
+ // the first time we successfully decode an incoming packet.
+ mFixRemote = false;
+ if (remote->ss_family == AF_INET) {
+ unsigned char *address =
+ (unsigned char *)&((sockaddr_in *)remote)->sin_addr;
+ if (address[0] == 10 ||
+ (address[0] == 172 && (address[1] >> 4) == 1) ||
+ (address[0] == 192 && address[1] == 168)) {
+ mFixRemote = true;
+ }
+ }
}
LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket,
@@ -318,16 +331,6 @@ void AudioStream::encode(int tick, AudioStream *chain)
sizeof(mRemote));
}
-bool AudioStream::isNatAddress(struct sockaddr_storage *addr) {
- if (addr->ss_family != AF_INET) return false;
- struct sockaddr_in *s4 = (struct sockaddr_in *)addr;
- unsigned char *d = (unsigned char *) &s4->sin_addr;
- if ((d[0] == 10)
- || ((d[0] == 172) && (d[1] & 0x10))
- || ((d[0] == 192) && (d[1] == 168))) return true;
- return false;
-}
-
void AudioStream::decode(int tick)
{
char c;
@@ -375,21 +378,11 @@ void AudioStream::decode(int tick)
MSG_TRUNC | MSG_DONTWAIT) >> 1;
} else {
__attribute__((aligned(4))) uint8_t buffer[2048];
- struct sockaddr_storage src_addr;
- socklen_t addrlen;
+ sockaddr_storage remote;
+ socklen_t len = sizeof(remote);
+
length = recvfrom(mSocket, buffer, sizeof(buffer),
- MSG_TRUNC|MSG_DONTWAIT, (sockaddr*)&src_addr, &addrlen);
-
- // The following if clause is for fixing the target address if
- // proxy server did not replace the NAT address with its media
- // port in SDP. Although it is proxy server's responsibility for
- // replacing the connection address with correct one, we will change
- // the target address as we detect the difference for now until we
- // know the best way to get rid of this issue.
- if ((memcmp((void*)&src_addr, (void*)&mRemote, addrlen) != 0) &&
- isNatAddress(&mRemote)) {
- memcpy((void*)&mRemote, (void*)&src_addr, addrlen);
- }
+ MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
// Do we need to check SSRC, sequence, and timestamp? They are not
// reliable but at least they can be used to identify duplicates?
@@ -409,8 +402,12 @@ void AudioStream::decode(int tick)
if (length >= 0) {
length = mCodec->decode(samples, &buffer[offset], length);
}
+ if (length > 0 && mFixRemote) {
+ mRemote = remote;
+ mFixRemote = false;
+ }
}
- if (length != mSampleCount) {
+ if (length <= 0) {
LOGD("stream[%d] decoder error", mSocket);
return;
}
@@ -461,18 +458,15 @@ private:
EC_ENABLED = 3,
LAST_MODE = 3,
};
- int mMode;
+
AudioStream *mChain;
int mEventQueue;
volatile int mDtmfEvent;
+ int mMode;
+ int mSampleRate;
int mSampleCount;
int mDeviceSocket;
- AudioTrack mTrack;
- AudioRecord mRecord;
-
- bool networkLoop();
- bool deviceLoop();
class NetworkThread : public Thread
{
@@ -490,10 +484,7 @@ private:
private:
AudioGroup *mGroup;
- bool threadLoop()
- {
- return mGroup->networkLoop();
- }
+ bool threadLoop();
};
sp<NetworkThread> mNetworkThread;
@@ -504,9 +495,6 @@ private:
bool start()
{
- char c;
- while (recv(mGroup->mDeviceSocket, &c, 1, MSG_DONTWAIT) == 1);
-
if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
LOGE("cannot start device thread");
return false;
@@ -516,10 +504,7 @@ private:
private:
AudioGroup *mGroup;
- bool threadLoop()
- {
- return mGroup->deviceLoop();
- }
+ bool threadLoop();
};
sp<DeviceThread> mDeviceThread;
};
@@ -539,8 +524,6 @@ AudioGroup::~AudioGroup()
{
mNetworkThread->requestExitAndWait();
mDeviceThread->requestExitAndWait();
- mTrack.stop();
- mRecord.stop();
close(mEventQueue);
close(mDeviceSocket);
while (mChain) {
@@ -559,40 +542,9 @@ bool AudioGroup::set(int sampleRate, int sampleCount)
return false;
}
+ mSampleRate = sampleRate;
mSampleCount = sampleCount;
- // Find out the frame count for AudioTrack and AudioRecord.
- int output = 0;
- int input = 0;
- if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
- sampleRate) != NO_ERROR || output <= 0 ||
- AudioRecord::getMinFrameCount(&input, sampleRate,
- AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
- LOGE("cannot compute frame count");
- return false;
- }
- LOGD("reported frame count: output %d, input %d", output, input);
-
- if (output < sampleCount * 2) {
- output = sampleCount * 2;
- }
- if (input < sampleCount * 2) {
- input = sampleCount * 2;
- }
- LOGD("adjusted frame count: output %d, input %d", output, input);
-
- // Initialize AudioTrack and AudioRecord.
- if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
- mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
- AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
- LOGE("cannot initialize audio device");
- return false;
- }
- LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
-
- // TODO: initialize echo canceler here.
-
// Create device socket.
int pair[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
@@ -610,13 +562,11 @@ bool AudioGroup::set(int sampleRate, int sampleCount)
return false;
}
- // Give device socket a reasonable timeout and buffer size.
+ // Give device socket a reasonable timeout.
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
- if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) ||
- setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
- setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
+ if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
LOGE("setsockopt: %s", strerror(errno));
return false;
}
@@ -644,29 +594,10 @@ bool AudioGroup::setMode(int mode)
return true;
}
+ mDeviceThread->requestExitAndWait();
LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
mMode = mode;
-
- mDeviceThread->requestExitAndWait();
- if (mode == ON_HOLD) {
- mTrack.stop();
- mRecord.stop();
- return true;
- }
-
- mTrack.start();
- if (mode == MUTED) {
- mRecord.stop();
- } else {
- mRecord.start();
- }
-
- if (!mDeviceThread->start()) {
- mTrack.stop();
- mRecord.stop();
- return false;
- }
- return true;
+ return (mode == ON_HOLD) || mDeviceThread->start();
}
bool AudioGroup::sendDtmf(int event)
@@ -741,15 +672,16 @@ bool AudioGroup::remove(int socket)
return true;
}
-bool AudioGroup::networkLoop()
+bool AudioGroup::NetworkThread::threadLoop()
{
+ AudioStream *chain = mGroup->mChain;
int tick = elapsedRealtime();
int deadline = tick + 10;
int count = 0;
- for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
+ for (AudioStream *stream = chain; stream; stream = stream->mNext) {
if (!stream->mTick || tick - stream->mTick >= 0) {
- stream->encode(tick, mChain);
+ stream->encode(tick, chain);
}
if (deadline - stream->mTick > 0) {
deadline = stream->mTick;
@@ -757,12 +689,12 @@ bool AudioGroup::networkLoop()
++count;
}
- if (mDtmfEvent != -1) {
- int event = mDtmfEvent;
- for (AudioStream *stream = mChain; stream; stream = stream->mNext) {
+ int event = mGroup->mDtmfEvent;
+ if (event != -1) {
+ for (AudioStream *stream = chain; stream; stream = stream->mNext) {
stream->sendDtmf(event);
}
- mDtmfEvent = -1;
+ mGroup->mDtmfEvent = -1;
}
deadline -= tick;
@@ -771,7 +703,7 @@ bool AudioGroup::networkLoop()
}
epoll_event events[count];
- count = epoll_wait(mEventQueue, events, count, deadline);
+ count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
if (count == -1) {
LOGE("epoll_wait: %s", strerror(errno));
return false;
@@ -783,70 +715,125 @@ bool AudioGroup::networkLoop()
return true;
}
-bool AudioGroup::deviceLoop()
+bool AudioGroup::DeviceThread::threadLoop()
{
- int16_t output[mSampleCount];
+ int mode = mGroup->mMode;
+ int sampleRate = mGroup->mSampleRate;
+ int sampleCount = mGroup->mSampleCount;
+ int deviceSocket = mGroup->mDeviceSocket;
+
+ // Find out the frame count for AudioTrack and AudioRecord.
+ int output = 0;
+ int input = 0;
+ if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
+ sampleRate) != NO_ERROR || output <= 0 ||
+ AudioRecord::getMinFrameCount(&input, sampleRate,
+ AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
+ LOGE("cannot compute frame count");
+ return false;
+ }
+ LOGD("reported frame count: output %d, input %d", output, input);
+
+ if (output < sampleCount * 2) {
+ output = sampleCount * 2;
+ }
+ if (input < sampleCount * 2) {
+ input = sampleCount * 2;
+ }
+ LOGD("adjusted frame count: output %d, input %d", output, input);
- if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) {
- memset(output, 0, sizeof(output));
+ // Initialize AudioTrack and AudioRecord.
+ AudioTrack track;
+ AudioRecord record;
+ if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
+ AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
+ record.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
+ AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
+ LOGE("cannot initialize audio device");
+ return false;
}
+ LOGD("latency: output %d, input %d", track.latency(), record.latency());
- int16_t input[mSampleCount];
- int toWrite = mSampleCount;
- int toRead = (mMode == MUTED) ? 0 : mSampleCount;
- int chances = 100;
+ // TODO: initialize echo canceler here.
- while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
- if (toWrite > 0) {
- AudioTrack::Buffer buffer;
- buffer.frameCount = toWrite;
+ // Give device socket a reasonable buffer size.
+ setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
+ setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
- status_t status = mTrack.obtainBuffer(&buffer, 1);
- if (status == NO_ERROR) {
- memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size);
- toWrite -= buffer.frameCount;
- mTrack.releaseBuffer(&buffer);
- } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
- LOGE("cannot write to AudioTrack");
- return false;
- }
+ // Drain device socket.
+ char c;
+ while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
+
+ // Start your engine!
+ track.start();
+ if (mode != MUTED) {
+ record.start();
+ }
+
+ while (!exitPending()) {
+ int16_t output[sampleCount];
+ if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
+ memset(output, 0, sizeof(output));
}
- if (toRead > 0) {
- AudioRecord::Buffer buffer;
- buffer.frameCount = mRecord.frameCount();
-
- status_t status = mRecord.obtainBuffer(&buffer, 1);
- if (status == NO_ERROR) {
- int count = ((int)buffer.frameCount < toRead) ?
- buffer.frameCount : toRead;
- memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
- toRead -= count;
- if (buffer.frameCount < mRecord.frameCount()) {
- buffer.frameCount = count;
+ int16_t input[sampleCount];
+ int toWrite = sampleCount;
+ int toRead = (mode == MUTED) ? 0 : sampleCount;
+ int chances = 100;
+
+ while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
+ if (toWrite > 0) {
+ AudioTrack::Buffer buffer;
+ buffer.frameCount = toWrite;
+
+ status_t status = track.obtainBuffer(&buffer, 1);
+ if (status == NO_ERROR) {
+ int offset = sampleCount - toWrite;
+ memcpy(buffer.i8, &output[offset], buffer.size);
+ toWrite -= buffer.frameCount;
+ track.releaseBuffer(&buffer);
+ } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
+ LOGE("cannot write to AudioTrack");
+ break;
+ }
+ }
+
+ if (toRead > 0) {
+ AudioRecord::Buffer buffer;
+ buffer.frameCount = record.frameCount();
+
+ status_t status = record.obtainBuffer(&buffer, 1);
+ if (status == NO_ERROR) {
+ int count = ((int)buffer.frameCount < toRead) ?
+ buffer.frameCount : toRead;
+ memcpy(&input[sampleCount - toRead], buffer.i8, count * 2);
+ toRead -= count;
+ if (buffer.frameCount < record.frameCount()) {
+ buffer.frameCount = count;
+ }
+ record.releaseBuffer(&buffer);
+ } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
+ LOGE("cannot read from AudioRecord");
+ break;
}
- mRecord.releaseBuffer(&buffer);
- } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
- LOGE("cannot read from AudioRecord");
- return false;
}
}
- }
- if (!chances) {
- LOGE("device loop timeout");
- return false;
- }
+ if (chances <= 0) {
+ LOGE("device loop timeout");
+ break;
+ }
- if (mMode != MUTED) {
- if (mMode == NORMAL) {
- send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
- } else {
- // TODO: Echo canceller runs here.
- send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
+ if (mode != MUTED) {
+ if (mode == NORMAL) {
+ send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
+ } else {
+ // TODO: Echo canceller runs here.
+ send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
+ }
}
}
- return true;
+ return false;
}
//------------------------------------------------------------------------------
diff --git a/voip/jni/rtp/G711Codec.cpp b/voip/jni/rtp/G711Codec.cpp
new file mode 100644
index 0000000..091afa9
--- /dev/null
+++ b/voip/jni/rtp/G711Codec.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyrightm (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.
+ */
+
+#include "AudioCodec.h"
+
+namespace {
+
+int8_t gExponents[128] = {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+};
+
+//------------------------------------------------------------------------------
+
+class UlawCodec : public AudioCodec
+{
+public:
+ int set(int sampleRate, const char *fmtp) {
+ mSampleCount = sampleRate / 50;
+ return mSampleCount;
+ }
+ int encode(void *payload, int16_t *samples);
+ int decode(int16_t *samples, void *payload, int length);
+private:
+ int mSampleCount;
+};
+
+int UlawCodec::encode(void *payload, int16_t *samples)
+{
+ int8_t *ulaws = (int8_t *)payload;
+ for (int i = 0; i < mSampleCount; ++i) {
+ int sample = samples[i];
+ int sign = (sample >> 8) & 0x80;
+ if (sample < 0) {
+ sample = -sample;
+ }
+ sample += 132;
+ if (sample > 32767) {
+ sample = 32767;
+ }
+ int exponent = gExponents[sample >> 8];
+ int mantissa = (sample >> (exponent + 3)) & 0x0F;
+ ulaws[i] = ~(sign | (exponent << 4) | mantissa);
+ }
+ return mSampleCount;
+}
+
+int UlawCodec::decode(int16_t *samples, void *payload, int length)
+{
+ int8_t *ulaws = (int8_t *)payload;
+ for (int i = 0; i < length; ++i) {
+ int ulaw = ~ulaws[i];
+ int exponent = (ulaw >> 4) & 0x07;
+ int mantissa = ulaw & 0x0F;
+ int sample = (((mantissa << 3) + 132) << exponent) - 132;
+ samples[i] = (ulaw < 0 ? -sample : sample);
+ }
+ return length;
+}
+
+//------------------------------------------------------------------------------
+
+class AlawCodec : public AudioCodec
+{
+public:
+ int set(int sampleRate, const char *fmtp) {
+ mSampleCount = sampleRate / 50;
+ return mSampleCount;
+ }
+ int encode(void *payload, int16_t *samples);
+ int decode(int16_t *samples, void *payload, int length);
+private:
+ int mSampleCount;
+};
+
+int AlawCodec::encode(void *payload, int16_t *samples)
+{
+ int8_t *alaws = (int8_t *)payload;
+ for (int i = 0; i < mSampleCount; ++i) {
+ int sample = samples[i];
+ int sign = (sample >> 8) & 0x80;
+ if (sample < 0) {
+ sample = -sample;
+ }
+ if (sample > 32767) {
+ sample = 32767;
+ }
+ int exponent = gExponents[sample >> 8];
+ int mantissa = (sample >> (exponent == 0 ? 4 : exponent + 3)) & 0x0F;
+ alaws[i] = (sign | (exponent << 4) | mantissa) ^ 0xD5;
+ }
+ return mSampleCount;
+}
+
+int AlawCodec::decode(int16_t *samples, void *payload, int length)
+{
+ int8_t *alaws = (int8_t *)payload;
+ for (int i = 0; i < length; ++i) {
+ int alaw = alaws[i] ^ 0x55;
+ int exponent = (alaw >> 4) & 0x07;
+ int mantissa = alaw & 0x0F;
+ int sample = (exponent == 0 ? (mantissa << 4) + 8 :
+ ((mantissa << 3) + 132) << exponent);
+ samples[i] = (alaw < 0 ? sample : -sample);
+ }
+ return length;
+}
+
+} // namespace
+
+AudioCodec *newUlawCodec()
+{
+ return new UlawCodec;
+}
+
+AudioCodec *newAlawCodec()
+{
+ return new AlawCodec;
+}
diff --git a/voip/jni/rtp/GsmCodec.cpp b/voip/jni/rtp/GsmCodec.cpp
new file mode 100644
index 0000000..8d2286e
--- /dev/null
+++ b/voip/jni/rtp/GsmCodec.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyrightm (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.
+ */
+
+#include "AudioCodec.h"
+
+extern "C" {
+#include "gsm.h"
+}
+
+namespace {
+
+class GsmCodec : public AudioCodec
+{
+public:
+ GsmCodec() {
+ mEncode = gsm_create();
+ mDecode = gsm_create();
+ }
+
+ ~GsmCodec() {
+ if (mEncode) {
+ gsm_destroy(mEncode);
+ }
+ if (mDecode) {
+ gsm_destroy(mDecode);
+ }
+ }
+
+ int set(int sampleRate, const char *fmtp) {
+ return (sampleRate == 8000 && mEncode && mDecode) ? 160 : -1;
+ }
+
+ int encode(void *payload, int16_t *samples);
+ int decode(int16_t *samples, void *payload, int length);
+
+private:
+ gsm mEncode;
+ gsm mDecode;
+};
+
+int GsmCodec::encode(void *payload, int16_t *samples)
+{
+ gsm_encode(mEncode, samples, (unsigned char *)payload);
+ return 33;
+}
+
+int GsmCodec::decode(int16_t *samples, void *payload, int length)
+{
+ if (length == 33 &&
+ gsm_decode(mDecode, (unsigned char *)payload, samples) == 0) {
+ return 160;
+ }
+ return -1;
+}
+
+} // namespace
+
+AudioCodec *newGsmCodec()
+{
+ return new GsmCodec;
+}